So, you want to know how to get emails from GMail to manipulate in your Rails app right?

First let’s create our app and generate our main class:

$ rails app
$ cd app
$ script/generate scaffold task name:string description:text
$ rake db:migrate
$ rm -rf public/index.html

Map the tasks index action to be the root of the app:

#config/routes.rb
ActionController::Routing::Routes.draw do |map|
  map.resources :tasks
 
  map.root :tasks
end

At this point we have a working very simple app to manage our tasks list. Let’s start our server:

$ script/server

You can go to http://localhost:3000 and see our app running.
Now, create the mailer that will check gmail for us:

$ script/generate mailer MailReader

Edit the generated mailer to look like the above:

# app/models/mail_reader.rb
require 'net/pop'
 
class MailReader < ActionMailer::Base
  def receive(email)
    task = Task.new :name => email.subject, :description => email.body
    if email.has_attachments?
      email.attachments.each do |attachment|
        task.assets.create :data => attachment
      end
    end
  end
 
  def self.check_mail
    logger = RAILS_DEFAULT_LOGGER
 
    logger.info "Checking for emails..."
    Net::POP3.enable_ssl(OpenSSL::SSL::VERIFY_NONE) #This line raises error if ruby version &lt; 1.8.7
    Net::POP3.start("pop.gmail.com", 995, "your-email@gmail.com", "your-password") do |pop|
      if pop.mails.empty?
        logger.info "No emails found."
      else
        pop.mails.each do |email|
          begin
            logger.info "Retrieving mail..."
            MailReader.receive(email.pop)
            email.delete
          rescue Exception => e
            logger.error "[" + Time.now.to_s + "] " + e.message
          end
        end
      end
    end
    logger.info "Done."
  end
end

Note that your ruby version need to be 1.8.7 or higher.
Now we need to create our model that will keep the attachments and install the paperclip plugin:

$ script/plugin install git://github.com/thoughtbot/paperclip.git
$ script/generate model asset

Put this in the migration file:

# db/migrate/20090303181609_create_assets.rb
class CreateAssets < ActiveRecord::Migration
  def self.up
    create_table :assets do |t|
      t.string      :data_file_name
      t.string      :data_content_type
      t.integer     :data_file_size
      t.datetime    :data_updated_at
      t.references  :task
      t.timestamps
    end
  end
 
  def self.down
    drop_table :assets
  end
end

Run the migration:

$ rake db:migrate

Create the associations in the models:

# app/models/asset.rb
class Asset < ActiveRecord::Base
  belongs_to :task
 
  has_attached_file :data
end
# app/models/task.rb
class Task < ActiveRecord::Base
  has_many :assets
end

…and finally, modify the task show template to show the attachments:

  <!-- app/views/tasks/show.html.erb -->
 
  <b>Name:</b>
  <%=h @task.name %>
 
  <b>Description:</b>
  <%=h @task.description %>
 
  <% unless @task.assets.blank? -%>
 
  <b>Attachments:</b>
  <% @task.assets.each do |asset| -%>
    <%= link_to "Download \"#{asset.data_file_name}\"", asset.data.url %>
  <% end -%>
 
<% end -%>
 
<%= link_to 'Edit', edit_task_path(@task) %> |
<%= link_to 'Back', tasks_path %>

You can set up a cron job to check if there are new emails every two minutes by putting this your crontab file:

##__email_checker__
*/2 * * * * RAILS_ENV=production /usr/local/bin/ruby /home/mauricio/pdn-posts/how-to-pull-emails-from-gmail-to-rachments/app/script/runner MailReader.check_mail

And last but not least, the source code used for this post is hosted on github.