Tue, 24 Oct 06

Connecting to gmail with Ruby (or Connecting to POP3 servers over SSL with Ruby)

Short version (or, “I want to connect to gmail NOW”)

require 'pop_ssl' # I renamed the file from pop.rb to pop_ssl.rb to ensure I was requiring the correct version

username = 'YOUR_GMAIL_USERNAME@gmail.com'
password = 'YOUR_GMAIL_PASSWORD'

Net::POP3.enable_ssl(OpenSSL::SSL::VERIFY_NONE)
Net::POP3.start('pop.gmail.com', 995, username, password) do |pop|
  if pop.mails.empty?
    puts 'No mail.'
  else
    pop.each_mail do |mail|
      p mail.header
    end
  end
end

Medium version (or, “Let me know I’m connecting to the correct site, Dammit”)

This is identical to the short version except that we verify the ssl certificate this time round.

Net::POP3.enable_ssl(OpenSSL::SSL::VERIFY_PEER, '/PATH/TO/DOWNLOADED/cacert.pem')

Longer version (or, “Pray tell, how did you find this information sir”)

An explanation of how I got here. Feel free to ignore.

For a while I’ve wanted to play around with receiving emails within a rails app (with action mailer). I had an hour or two free the other evening and so started to play. First step was to take a look at the rails wiki and see that there’s already a page detailing exactly what I wanted to do. As I started reading, I was getting put off by the thought of configuring sendmail or some other ‘heavyweight’ solution. Luckily, someone has added a much better suggestion at the bottom of the page – using net/pop (or net/imap) to collect emails from a pre-configured mail server. Although I use imap for my own email provision, I wanted a pop server for testing. Aha, I thought, I’ll just set-up another gmail account and use that… And that’s where the problems started.

You see, gmail only accepts POP3 connections over SSL (on port 995), a feature not found in our beloved net/pop library. Hmm. Time for some help from google. The first page I came across described using stunnel to create an ssl tunnel to route standard net/pop traffic through. This sounded great, except that I couldn’t get stunnel (v4.16) to compile on mac os x, although I didn’t try too hard… The other point of interest in that original article was that the pop3 with ssl support was in development. The next step was to track down some mailing list threads that talked about the ssl support and hope for a patch. We’re in luck, the first patch was actually submitted in March 2004, with the second, accepted and committed, patch coming in April 2004. As per the last message in the second thread, the patch was accepted into core, and is now available in the 1.9 release. So, we don’t even need to patch our existing copy of net/pop, we can just download the newer version. I named this downloaded version as pop_ssl, to avoid confusion, and placed it in my ruby load path.

Next step was to follow the example on the net/pop3 page, and, with the addition of the Net::POP3::enable_ssl directive, try to connect. Hmm, things still weren’t working quite right. I was getting the following error.

OpenSSL::SSL::SSLError: certificate verify failed

Some more googling led me to this post by Greg Houston. It turns out that the error is actually raised in the OpenSSL layer. It is caused by us trying to verify the server certificate without having the correct trusted root certificate. It turns out that we can either disable the verification (by using Net::POP3::enable_ssl(OpenSSL::SSL::VERIFY_NONE)), or we can verify against a trusted root certificate bundle, like the one supplied by cURL. To verify using the certificate bundle from cURL (or similar), we would amend the above line of code to Net::POP3.enable_ssl(OpenSSL::SSL::VERIFY_PEER, File.dirname(__FILE__) + '/PATH/TO/DOWNLOADED/cacert.pem').

I can finally now get on with my rails app to retrieve emails from gmail.

Conclusion