Connecting to gmail with Ruby (or Connecting to POP3 servers over SSL with Ruby)
Short version (or, “I want to connect to gmail NOW”)
- Download the pop3 library from Ruby HEAD (Ruby 1.9) (download file)
- Use the following script to get started (making sure that you explicitly reference the downloaded pop3 file)…
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.
- Follow the first step above (i.e. download new version of pop3 lib).
- Download the CA Root Certificates bundle from cURL site (download file)
- Copy the code above but change the Net::POP3.enable_ssl line to read…
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
- I’ve spent a lot more than the intended couple of hours investigating this stuff, yet still have no rails app receiving emails (although I’m a lot closer now…)
- There’s very little information on the ssl enabled libraries (net/https, net/pop, http-access2 to name but a few) in ruby. Maybe everybody else just knows about this stuff already, but I’m certainly pretty unclear.
- I have a feeling that it should be possible to use net/https to connect (unverified) to a site that uses ssl and obtain the certificate for use in subsequent verified connections. Indeed, another document hosted on curl.haxx.se seems to indicate that this is possible.
- I still know very little about ssl and certificates.
- I hope that what little information is here can help someone else in a similar situation.