Custom mail delivery method in Rails 3.*

Rails 3 allows you to specify a custom mail delivery method in addition to the default options smtp, sendmail, test and file. You can do this by specifying the class name of your mail delivery handler in the config file like this:

config.action_mailer.delivery_method = MyCustomDelivery

And the interface your class needs to implement is:

class CustomDelivery
  def deliver!(mail)
  end
end

How does this work?

Say you have a mailer class for sending out a welcome email:

class Notifier < ActionMailer::Base
  def welcome
    mail(:to => "receiver@test.com",
         :from => "sender@test.com",
         :subject => "Testing custom mail delivery methods",
         :body => "Hello World")
  end
end

When you try to deliver a welcome email, the Mail object constructed in the “welcome” method is sent to the deliver! method of your delivery class.

mail = Notifier.welcome # Construct a mail object
mail.deliver            # Deliver the mail with the delivery method specified in the config

In your deliver! method you will then have full access to the mail object:

class CustomDelivery
  def deliver!(mail)
    puts mail.to       # receiver@test.com
    puts mail.from     # sender@test.com
    .
    .
    .
  end
end

Why is this useful?

Consider a rails application like Twitter where different notification emails go out when people start following each other, send direct messages to each other, etc. Testing these emails by writing mailer tests is good. But it will also be nice to view the actual email that will be delivered to the users. To accomplish this we can write a custom SMTP (catch all) delivery class which inherits from the default Mail::SMTP class.

require 'rubygems'
require 'mail'

class CustomSmtpDelivery < ::Mail::SMTP 
  # SMTP configuration (could be possible to pass the settings from the config file)   
  def initialize(values)     
    self.settings = {:address => "smtp.gmail.com",
                     :port => 587,
                     :domain => 'yourdomain',
                     :user_name => "username",
                     :password => "password",
                     :authentication => 'plain',
                     :enable_starttls_auto => true,
                    }.merge!(values)
  end
  attr_accessor :settings

  def deliver!(mail)
    # Redirect all mail to your inbox
    mail['to'] = "youremail@domain.com"
    mail['bcc'] = []
    mail['cc'] = []
    super(mail)
  end
end

In this class we first setup our SMTP configuration and in the deliver! method, we are basically redirecting all outgoing email to our personal email by modifying the “to field” and then passing on the modified mail object to the superclass (Mail::SMTP) deliver! method.

View source here: https://github.com/DushyanthMaguluru/custom_mail_delivery


Testing subdomain sites the easy way

You have two options to test sites that use multiple subdomains:

  1. Add each and every subdomain to your host file
  2. 127.0.0.1 site1.mywebapp.local
    127.0.0.1 site2.mywebapp.local
    etc.

  3. Setup a DNS server (Dnsmasq or Bind)

Both these approaches have their disadvantages. Updating your hosts file can become tedious, especially if your site supports dynamic subdomain creation. And setting up a DNS server takes some effort.

Tim Pope found a simple workaround for this problem. As he mentions here:

“I grabbed smackaho.st and made it a localhost wildcard, pointing *.smackaho.st at 127.0.0.1″

So that means you can now use URLs like http://site1.mywebapp.smackho.st or http://site2.mywebapp.smackho.st without having to add them to your hosts file.

One issue remains: say my development box is at 192.168.0.100 in my home network and my Droid is at 192.168.0.110, how would I be able to access the sites on my Droid? One way is to update the hosts file on the Droid, but you need root access for that.

So I grabbed dm7.me and made it point to my dev machine’s local ip address: *.dm7.me points to 192.168.0.100. Now I can access my development sites from all the devices on my network without having to update the hosts file on each and every one of them.


Using ActiveMerchant with Payflow Pro

Connection parameter’s for Payflow gateway:

  1. VENDOR => The merchant login ID that you created when you registered
  2. USER => User id of the user responsible for processing transactions (Usually same as the VENDOR unless you created additional users and assigned appropriate roles).
  3. PARTNER => From whom did you purchase your account? If from PayPal, then use the “PayPal”
  4. PWD => The password for the user mentioned in step (2)
gateway = ActiveMerchant::Billing::PayflowGateway.new(
  :user => 'user-name',        #USER
  :login => 'merchant-id',     #VENDOR
  :partner => 'partner-name',  #PARTNER
  :password => 'my-password'   #PWD
)

Hello world!

def print_hello
  puts "Hello world!"
end

Follow

Get every new post delivered to your Inbox.