Codebeerstartups

Every Dog has one Blog

How to Fetch and Parse Emails in Ruby on Rails

Last weekend I was working on an mini hackathon and launched a group emailing service. EmailList.io. The task was to setup an email server, how to fetch and parse emails in ruby on rails forward it to respective group members. Last part was pretty simple. In this post I am just talking about “How to fetch and parse emails in ruby on rails.”

To fetch email using POP/IMAP you check out a gem ie mailman. Here is the sample code for the same:

  1. Install the gem
  2. Create a script file in scripts folder ie mailman_server and just paste the code below, which itself is pretty clear. Check inline comments.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/usr/bin/env ruby
require "rubygems"
require "bundler/setup"
require "mailman"
#Mailman.config.logger = Logger.new("log/mailman.log")  # uncomment this if you can want to create a log file
Mailman.config.poll_interval = 3  # change this number as per your needs. Default is 60 seconds
Mailman.config.pop3 = {
  server: 'pop.gmail.com', port: 995, ssl: true,
  username: "GMAIL_USERNAME",
  password: "GMAIL_PASSWORD"
}
  Mailman::Application.run do
  default do
    begin
    p "Found a new message"
    p message.from.first # message.from is an array
    p message.to.first # message.to is an array again..
    p message.subject
    rescue Exception => e
      Mailman.logger.error "Exception occurred while receiving message:n#{message}"
      Mailman.logger.error [e, *e.backtrace].join("n")
    end
  end
end

So far its pretty easy, but the question is how to parse the email body as html, text and parse attachments. Now take a look on this. Pretty simple.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
if message.multipart?
  email_html = message.html_part.body.decoded  #parsing of html content of the email
  email_text = message.text_part.body.decoded  # parsing of text content of the email
  email_attachments = []   # an array which can be used to store object records of the attachments..
  message.attachments.each do |attachment|
    file = StringIO.new(attachment.decoded)
    file.class.class_eval { attr_accessor :original_filename, :content_type }
    file.original_filename = attachment.filename
    file.content_type = attachment.mime_type
    attachment = Attachment.new    # an attachment model and all the attachments are saved here...
    attachment.attached_file = file
    attachment.save
    email_attachments << attachment   # adding all attachment objects one by one in the array...
  end
else
  email_html = message.body.decoded    # in this case its a plain email so html body is same as text body..
  email_text = message.body.decoded
  email_attachments = []   # no attachments :)
end

Once you have parsed all the attributes from the email ie to, from, email attachments now you can easily pass it to delayed job or something like creating a ticket or what ever you want to do as per you needs ;)

If you are facing any issues. Checkout the source code files at github. Still if you have any doubts contact me or you can comment on the blog post itself.

Comments