Wednesday, March 26, 2008

Validating Email Addresses with Ruby

After my post on how to send email thru action mailer I thought of writing how to validate that email address and thought it would be useful for all.

Here it goes

In any application in which a user enters an email address, there is the very real possibility that the user will make a typo and your application will end up with an invalid address. You can have them enter it twice, but this seems clunky. And you can, of course, send an email with an activation link, which provides the only true validation, but there’s no need to bother sending the email if you know the address is no good. Furthermore, once you’re past the page where the user enters their email address, you’ve missed your chance to tell them there’s something wrong and they should correct it.

So you really should do what you can to validate the address when the user enters it. I recently made a simple addition to my applications that helps a lot: verify that the domain name is valid.

It’s surprisingly easy to do—especially with a little help from Peter Cooper’s excellent Beginning Ruby, which has a very useful chapter on network programming. The following code is adapted from his examples:

require 'resolv'
def validate_email_domain(email)
domain = email.match(/\@(.+)/)[1]
Resolv::DNS.open do |dns|
@mx = dns.getresources(domain, Resolv::DNS::Resource::IN::MX)
end
@mx.size > 0 ? true : false
end

This example makes use of the Ruby standard library “resolv”, so you need to require it first.

The first step is to separate the domain name from the rest of the email address. The regular expression captures the part of the string that follows the @ symbol.

Then the code creates a new DNS resolver object and queries the resolver for an MX (mail exchanger) resource at the specified domain. This returns an array, which will be empty if there is no MX record for the domain.

(Note: In a previous version of this article, I used Resolv.getaddress to see if there is a DNS entry for the domain, instead of checking for an MX record. This approach works most of the time, but it rejects any domain for which there is no A record. If a domain is used only for email and not for a web server, there might not be an A record. Also, some domains have an A record only for www.domain.com, which will also fail the simple getaddress test.)

You can use something like the following in the validate method within the appropriate model:

unless email.blank?
unless email =~ /^[a-zA-Z][\w\.-]*[a-zA-Z0-9]@[a-zA-Z0-9][\w\.-]*[a-zA-Z0-9]\.[a-zA-Z][a-zA-Z\.]*[a-zA-Z]$/
errors.add(:email, "Your email address does not appear to be valid")
else
errors.add(:email, "Your email domain name appears to be incorrect") unless validate_email_domain(email)
end
end

I first check to make sure the email address is not blank, because that’s detected by a simple validates_presence_of :email statement that produces a different error message.

Then I make sure that the email address is at least syntactically reasonable, with a rather ugly regular expression, before bothering to check the DNS.

It should be noted that the regex I use here isn’t designed to cover all of the RFC2822 cases, nor with other RFC drafts dealing with non-ASCII addressing.

An even better approach would be to use an observer to validate the address with an Ajax call before the user submits the form.

It is possible to take this a step further by sending the SMTP server referenced in the MX record a “RCPT TO:” command. In theory, this would check that the user name is valid as well as the domain name. This takes additional time, however, and I’ve read that the response from mail servers is often not reliable. If anyone has tried this, I’d appreciate any feedback on how well it worked.

Thursday, March 6, 2008

Actionmailer

Action Mailer is the Rails component that enables applications to send and receive e-mail. In this chapter we will see how to send an email using Rails. So lets start with creating a emails project using following command.

C:\ruby\> rails emails

This will create required framework to proceed. Now we will start with configuring Action Mailer.

Action Mailer - Configuration

Following are the steps you have to follow to complete your configruation before proceeding with actual work:

Go into config folder of your emails project and open environment.rb file and add the following line at the bottom of this file.


ActionMailer::Base.delivery_method = :smtp

This tells ActionMailer that you want to user SMTP server. You can also set it to be :sendmail if you are using a Unix-based operating system such as Mac OS X or Linux.

Add the following lines of code to the bottom of your environment.rb as well.

ActionMailer::Base.server_settings = {
:address => "smtp.dhavalparikh.co.in",
:port => 25,
:domain => "dhavalparikh.co.in",
:authentication => :login,
:user_name => "username",
:password => "password",
}


The values given in double quotes will be different for your SMTP server. You can take this information from your Inernet Service Provider if you already don't know. You don't need to change port number 25 and authentication type if you ar eusing standard SMTP server.

Next step will be to create a mailer

Generate a mailer:
Use the following command to generate a mailer as follows:

C:\ruby\> cd emails
C:\ruby\emails> ruby script/generate mailer Emailer


This will create a file emailer.rb in app\models directory. Check the content of this file is as follows:

class Emailer > ActionMailer::Base
end


Let's create one method as follows.

class Emailer > ActionMailer::Base
def contact(recipient, subject, message, sent_at = Time.now)
@subject = subject
@recipients = recipient
@from = 'no-reply@yourdomain.com'
@sent_on = sent_at
@body["title"] = 'This is title'
@body["email"] = 'sender@yourdomain.com'
@body["message"] = message
@headers = {}
end
end


The contact method has four parameters a recipient, subject, message and a sent_at, which defines when the e-mail is sent. The method also defines six standard parameters that are a part of every ActionMailer method:

@subject defines the e-mail subject.

@body is a Ruby hash that contains values with which you can populate the mail template. You created three key-value pairs: title, email, and message

@recipients is a list of the people to whom the message is being sent.

@from defines who the e-mail is from.

@sent_on takes the sent_at parameter and sets the timestamp of the e-mail.

@headers is another hash that enables you to modify the e-mail headers. For example, you can set the MIME type of the e-mail if you want to send either plain text or HTML e-mail.

Now we will create a mailer template which is just text with standard Rails placeholders scattered throughout.

Put following code in app/views/contact.rhtml file

Hi!

You are having one email message from with a tilte


and following is the message:


Thanks


Next we will create a controller for this application as follows:

C:\ruby\emails> ruby script/generate controller Emailer


Now lets define a controller method in emailer_controller.rb which will call Model method to send actual email as follows:

class EmailerController < email =" @params[" recipient =" email[" subject =" email[" message =" email[" text =""> 'Message sent successfully'
end
end


To deliver e-mail using the mailer.s contact method, you have to add deliver_ to the beginningof the method name. You add a return if request.xhr? line so that you can escape to Rails Java Scripr (RJS) if the browser does not support JavaScript and then tell the method to render a text message.

You are almost done except to prepare a screen from where you will get user information to send email. So lets define one screen method index in controller and corresponding view:

Add following code in emailer_controller.rb file

def index
render :file => 'app\views\emailer\index.rhtml'
end


Now let's define our view in app\views\emails\index.rhtml

Send Email


bracket