1

I woul like to get unseen mails "as soon as possible", using a Ruby (2.1) script to implement IMAP IDLE ("push notify") feature.

With the help of some guys (see also: Support for IMAP IDLE in ruby), I wrote the script here: https://gist.github.com/solyaris/b993283667f15effa579

def idle_loop(imap, search_condition, folder)
  # https://stackoverflow.com/questions/4611716/how-imap-idle-works
  loop do
    begin
      imap.select folder
      imap.idle do |resp|

        #trap_shutdown

        # You'll get all the things from the server. 
        #For new emails you're only interested in EXISTS ones
        if resp.kind_of?(Net::IMAP::UntaggedResponse) and resp.name == "EXISTS"

          # Got something. Send DONE. This breaks you out of the blocking call
          imap.idle_done
        end
      end

      # We're out, which means there are some emails ready for us.
      # Go do a search for UNSEEN and fetch them.
      retrieve_emails(imap, search_condition, folder) { |mail| process_email mail}

    #rescue Net::IMAP::Error => imap_err
      # Socket probably timed out
    #  puts "IMAP IDLE socket probably timed out.".red

    rescue SignalException => e
      # https://stackoverflow.com/questions/2089421/capturing-ctrl-c-in-ruby
      puts "Signal received at #{time_now}: #{e.class} #{e.message}".red      
      shutdown imap

    rescue Exception => e
      puts "Something went wrong at #{time_now}: #{e.class} #{e.message}".red
      imap.noop
    end
  end
end

Now, all run smootly at first glance, BUT I have the exception

Something went wrong: SSL_write: bad write retry

at this line in code: https://gist.github.com/solyaris/b993283667f15effa579#file-idle-rb-L189

The error happen when I leave the script running for more than... say more than 30 minutes.

BTW, the server is imap.gmail.com (arghh...), and I presume is something related to IMAP IDLE reconnection socket (I din't read yet the ruby UMAP library code) but I do not understand the reason of the exception;

Any idea for the reason if the exception ? Just trap the exception to fix the issue ?

thanks giorgio

UPDATE

I modified a bit the exception handling (see gist code: https://gist.github.com/solyaris/b993283667f15effa579)

Now I got a Net::IMAP::Error connection closed I just restart the IMAP connection and it seems working... Sorry for confusing, anyway in general any comments on code I wrote, IDLE protocol correct management, are welcome.

Community
  • 1
  • 1
Giorgio Robino
  • 2,148
  • 6
  • 38
  • 59

1 Answers1

1

The IMAP IDLE RFC says to stop IDLE after at most 29 minutes and reissue a new IDLE command. IMAP servers are permitted to assume that the client is dead and has gone away after 31 minutes of inactivity.

You may also find that some NAT middleboxes silently sabotage your connection long before the half-hour is up, I've seen timeouts as short as about two minutes. (Every time I see something like that I scream "vivat ipv6!") I don't think there's any good solution for those middleboxes, except maybe to infect them with a vile trojan, but the bad solutions include adjusting your idle timeout if you get the SSL exception before a half-hour is up.

arnt
  • 8,949
  • 5
  • 24
  • 32
  • yes... in case of imap.gmail.com server, I tested (see my UPDATE comment in original question) a disconnection in almost 1 hour. I was unaware about the 29 minutes RFC guideline. Now I understand why someone do something like `Thread.start {loop { imap.idle_done; sleep 600}}` so retarting the IDLE every 10 minutes... thanks – Giorgio Robino Dec 15 '14 at 10:45