TUTORIAL - How to create and manage Mailers and Observers

=======================================================
| (TUTORIAL) - How to Create and Manage Your Mailers |

Key Notes: Our pretend rails app is going to be called (mailbag). If I
reference our rails application at any point in this tutorial, I will
use mailbag as a descriptive reference. I’m going to assume you know
how to create a starting rails application. I’m also going to assume
you understand the MVC structure (Model/View/Controller) and how to find
environment.rb, routes.rb, and that you also have the ability to
navigate through your rails application.

For this tutorial, it would be best that you go ahead and create a
mailbag rails application and follow along with your test app. I’m not
going to go into detail on how to setup sweepers in this tutorial.
However, you’ll be able to understand why they have their own folder
structure once we’re finished with the tutorial.

==Prerequisites==

If you are using Ruby 1.8.6 or lower you will also have to download a
TLS plugin:
GMail SMTP with Ruby on Rails and ActionMailer
If you are using Ruby >= 1.8.7 or Ruby >= 1.9 you DO NOT need the
plugin.

– Create your Rails app for mailbag
– You can use any database (I use mysql)
– Run your rake db:create to create your database
– Keep your rails app open in your IDE/editor environment
– Follow the tutorial below and have some fun :slight_smile:

(Opening)

I see a lot of people asking about mailers and I remember when thinking
about mailers felt a lot like ruminating on Sunday night in preparation
for a Monday morning work day. Well, hopefully when this tutorial is
finished, you will no longer feel this way.

I’m going to break down the tutorial into multiple pieces for better
clarity and readability.

=======================================================
What you will accomplish in this tutorial

When you are finished, you’ll be able to use a Google Mail account
(gmail account) to process all mail for your site, have a solid
understanding of observers and how to use them, and will be able to send
both text or html emails to any of your site visitors. In addition, your
mailers will be better organized.

TUTORIAL ONE:

Organizing your Mailers into an easy-to-read structure

Before we start with mailers, wouldn’t it be nicer to have them in an
organized structure? If we didn’t organize them, they would be
scattered across many different folder paths. With rails and a few
lines of code, you can organize all of your mailers, observers, and
sweepers into their own unique folder structure.

  1. Open your Config → Environment.rb file.

  2. Place in the following code:
    (code) environment.rb · GitHub

  3. Create your physical folder structure. Inside of your mailbag →
    app directory, create sub-directories for mailers, observers, and
    sweepers.

Directory Structure

\mailbag
– \app
|
– \mailers
– \observers
– \sweepers

  1. Create a mailers view directory to hold all of our mailer views.
    This views sub-directory will be located in mailbag → app → mailers.

Directory Structure

\mailbag
– \app
|
– \mailers
|
– \views

  1. Create an application_mailer.rb file that will be located in mailbag
    → app → mailers.
    (code) application_mailer.rb · GitHub

Final Directory Structure

\mailbag
– \app
|
– \mailers
|
– \views
– application_mailer.rb
– \observers
– \sweepers

The final directory structure is also shown in a picture that you can
view to compare notes with:


Summary:

So, what have we done here? Well, first we let our rails environment
know through the environment.rb file that we will be loading paths to
our new directories. We also created an ApplicationMailer class that is
part of ActionMailer::Base and declared where our template views would
be located within that file. By doing so, we now control where all of
our mailers will be located. And, this means we can now hold all of our
mailers in one central location.

By itself, it does nothing at this point. All we’ve done is organized
where our mailers will operate from.

TUTORIAL TWO:

Creating a Gmail account and setting up email configuration

The next step we want to do is create a default mail account that will
handle our email requests. I could have gone into depth on how to use a
linux mail based system or any other open source mail environment. The
reason why I chose Gmail is because it’s simple and there have been a
lot of questions on how to use gmail with rails.

With a linux based email system (like postfix), it can be very difficult
to understand how to secure your environment, how to properly post
records, how to manage email logs, and even how to make sure you don’t
receive email relay rejections due to poor configuration. With Gmail,
you can set aside many of these worries and start emailing right away.

The first step you want to do is go to http://gmail.com and create an
account. Remember your username and your password. That’s all you’ll
need to to configure your email account in rails. I’ll help you do the
rest. Once you have everything created, mosey on down to step 1.

=========================================================
Adding email to your Rails Environment

The first thing we are going to do here is decide where we want our
email information to be located. You could place it inside
environment.rb but I find that this can clutter things up a bit. The
email is going to be used in your entire rails application and the email
information isn’t going to change. Therefore, we can place it in an
area where it can be managed easily.

  1. Create a file called email.rb inside of your config → initializers
    folder. Place the following code inside that file:
    (code) email.rb · GitHub (look at email.rb)

Explanation of the fields here:

:enable_starttls_auto => by default this is set to true for >= 1.8.7 and

= 1.9 ruby platforms
:address => defines the outbound smtp server. The default is set to
localhost.
:port => gmail uses port 587 in their remote mail configuration
:domain => this is really only used if you are specifying a HELO domain
(telnet)
:authentication => without plain authentication, gmail will not work
:user_name => this is the user name you signed up with on gmail
:password => this is the password you signed up with on gmail
:tls => true

  1. Alter your environment.rb file with a few more config lines.
    (code) email.rb · GitHub (look at environment.rb)

Summary:

When your rails application starts, the initializer for email.rb is
initiated and ActionMailer knows the settings to use for your mail
environment. In additiion, the config lines specify to deliver mail, to
raise delivery errors, and to specify the encoding used on emails. The
reason I place these in the tutorial is to let you be aware of their
settings and also so you have the ability to modify and change settings
during development and testing. You now have the ability to use email
in your rails application. Let’s setup a quick contact mailer for your
site and see how it works. Visit the next tutorial.

TUTORIAL THREE:

Setting Up a Messages Repository and Contact Mailer

Let’s generate a scaffold that will hold our messages and utilize our
contact form.

./script/generate scaffold message name:string company:string
phone:string email:string subject:string body:text

You should have a controller, a model, several views, and a database
migration.

Look at the following gist to ensure that your scaffold matches. You
want to copy and paste all the code into each of your files to ensure it
does match:
code: message.rb · GitHub

For now, don’t worry about your views. If you are having trouble
understanding the file names in the gist, or what a controller, model,
route, etc. are, you are probably not ready to handle mail in your
application. It’s okay if this is true, and you can continue to attempt
to follow-along with this tutorial and ask questions afterwards. Your
database migration will have an entirely different name. Just make
certain that contents are the same.

Go ahead and run the command ‘rake db:migrate’ to migrate your database
to the current schema.

As you can see by the gist, I’ve added some validation to our model.
Make sure you copy the validations into your own model. Validations are
important, especially with email forms. In our message model, the only
fields I’m validating are:

:name, :subject, :body, and :email

I’m not worried about :company and :phone because those fields are not
required for visitors to submit an email to me. However, if you want to
require your visitors to fill in every single field within your form,
you can add further validations to your model to account for this.

Let’s test our MVC and see if the server recognizes what we’ve done so
far. Run your application and navigate to messages. As I’m using
mongrel, my url for development is:

http://localhost:3000/messages

… yours may be a different url and that’s fine. If your app is running
fine and you can see this page, you are in good shape. Let’s continue.

=========================================================
Observers and not using them

The concept of observers was a bit mind-boggling for me but once I
became accustomed to using them, it was very easy to understand. You
can think of an observer as someone that’s watching for some type of
event to occur and then reacts to it. It’s the man in the rain coat
with the dark shades and the umbrella that’s stalking your house waiting
for something to happen. Once it does, it reacts accordingly.

In our contact form we’re not going to setup an observer. Mainly we’re
doing this so you can have an understanding and an appreciation for why
you should use observers in rails. Without knowing what it’s like to
not use an observer, you’d never understand what it’s like to have one.

  1. Create a contact_mailer.rb file in your app → mailers directory.
    Go ahead and use the code below to fill in this file.
    code: contact_mailer.rb · GitHub

So, let’s look over the code:

def message(message)
subject message.subject
body :message => message
recipients “[email protected]
from message.email
sent_on Time.now
end

It looks pretty similar to a standard email. It contains a subject, a
body, houses a recipient (like using TO:), a from (like using FROM:) and
has a time stamp. The one thing you’ll want to change here is the
recipients field. You should place in a test email address that you
have access to that can receive the email. The file name called
contact_mailer is pretty descriptive in itself. It lets you know that
this file is used for contact mailing. Because the file exists in our
mailers directory as a class, we can call upon this class anytime we
need to use this specific mailer.

  1. You also need to create the views for your contact mailer and allow
    the ability to handle multipart emails. You’ll do this by creating a
    contact_mailer folder within your app → mailers → views directory.

\mailbag
– \app
|
– \mailers
|
– \views
|
– \contact_mailer

Inside of the contact_mailer folder you are going to create two .erb
views. They will be:

message.text.html.erb
message.text.plain.erb

The .html and the .plain are content types used by your contact mailer.
By specifying html you can deliver an html view to any recipient that is
able to receive html. By specifying plain, you handle deliveries to
recipients that can only view text. By providing both files, you are
able to handle both types of content deliveries. Go ahead and add some
code to both of those files via this link here:
code: message.text.html.erb · GitHub

So, the million dollar question is how do we let rails know that when
someone creates a new message, it should deliver it through our
ContactMailer class. Ah, the keyword here (deliver).

Open up your messages_controller.rb file and find the method for create.
We’re going to let rails know that when a new message is created, it
should deliver it to our admin. We can do this with one line:

ContactMailer.deliver_message(@message)

This will go after we save the message in our create function. Go ahead
and look over the code at gist to ensure your’s looks the same:
code: messages_controller.rb · GitHub

When a visitor comes to your site and sends you a message, after the
message is dynamically saved to the database, it gets delivered to the
recipient through the ContactMailer class.

Let’s test it out!

  1. Open your URL to messages:

http://localhost:3000/messages

  1. Click on new.

  2. Type in a test message and click create.

  3. Check your email to see if you received the test email. If you
    didn’t, review this section and make sure everything matches correctly.
    If you did, great!


Summary:

At this point you are able to send mail with your rails app. You have
all of your mailers and views organized, your email accounts and
configurations setup, and you are able to test a contact mailer on your
site. In addition, messages that are created are automatically saved in
a database so you can cross-reference mail on your site. We didn’t
secure the actions from visitors but that’s another piece for another
time. If you’ve made it this far without hiccups, pat yourself on the
back. Let’s continue on to the next section.

TUTORIAL FOUR:

Creating User Authentication

Normally, I wouldn’t go into user authentication. But, for this
tutorial, mailers and observers are perfect for handling user
authentication mailers. Therefore, I’m going to get you starterd with
setting up user authentication, and also tidy up our app a little bit so
we can work with it easier.

Pre-requisites:

You need to install a couple of gems for starters (no plugins are
required here)

gem install restful_authentication (I’m using 1.1.6 right now for this
app)
gem install acts_as_state_machine (I’m using 2.1.20080704 right now for
this app)

If you have any issues with gem installations, you can go ahead and find
plugins for these two pieces and install them and skip the next section.
However, I’d rather you use gems so that you are following this tutorial
exactly.

Once these gems are installed, we’re going to apply some configurations
to environment.rb and then freeze our app.

Make the following changes to environment.rb (add the following):

config.gem “acts_as_state_machine”
config.gem “restful_authentication”

code: environment.rb · GitHub

If you are using plugins, don’t worry about adding the config lines.

Now, let’s go ahead and freeze our gems and rails. Run the following
commands:

rake rails:freeze:gems

… and then …

rake gems:unpack:dependencies

After doing this, you’ll see that the Vendors folder now contains a gems
folder with restful_authentication and acts_as_state_machine in them and
in addition, you have a rails folder that contains the latest rails
version. This is because we added config lines telling our application
that these gem dependencies were required. For those of you using
plugins, you won’t have a gems folder. You’ll only have a plugins
folder with the same two pices, and a rails folder. Pat yourself on the
back for another job well done.

Great! So our app is now frozen to the latest requirements needed for
this tutorial to work properly. Let’s continue…

The next thing we are going to do is create our user authentication
environment. Before you begin, “do not” migrate your database after
completing this task. You will be making many changes before performing
the migration itself. Let’s start by opening a console and doing the
following:

./script/generate authenticated user sessions --include_activation
–stateful

You should see a lot of items being created (controllers, models, views,
db migration, etc.) Again, do not migrate right now. Let’s go ahead
and open up our db migration file called “###########_create_users.rb”
where # means a digit in db → migrate.

While this schema is okay, it won’t serve our purposes. We’re going to
erase everything in this file and add our own. Use the code here:
code: xxxxxxxxxxxx_create_users.rb · GitHub

Make sure you look inside the schema file you just populated and change
the admin email and password fields and the test email and password
fields for both the admin and test users that will be created when you
do eventually migrate your database to the current version.

Do not migrate your database yet. :slight_smile: Be patient…

Now then, look in your app → models directory and you’ll notice that
in addition to user.rb (our user model), a user_mailer.rb and
user_observer.rb file were created. Well, we already have an organized
structure for mailers and observers so let’s move those two files to
their correct directories.

  1. Move user_observer.rb to your app → observers folder.
  2. Move user_mailer.rb to your app → mailers folder.
  3. Create a folder called user_mailer in your app → mailers → views
    folder.

mailbag
– \app
|
– \mailers
|
– \views
|
– \user_mailer

  1. Create the following view erb files in your user_mailer folder (they
    can be empty - don’t worry we’ll fill them in later)

– activation.text.html.erb
– activation.text.plain.erb
– forgot_password.text.html.erb
– forgot_password.text.plain.erb
– reset_password.text.html.erb
– reset_password.text.plain.erb
– signup_notification.text.html.erb
– signup_notification.text.plain.erb

  1. Go under your app → views and delete the old user_mailer folder
    completely. You don’t need this anymore.

  2. While we’re at it, go ahead and delete the messages_helper.rb and
    sessions_helper.rb files from your app → helpers folder.

Now then, things are a little cleaner in your app. We still have a few
more things to do before we perform our migration.

  1. Open up your application_controller.rb file in app → controllers
    and delete all of the code and replace it with the following code:
    code: application_controller.rb · GitHub

  2. Open up your sessions_controller.rb file in app → controllers and
    “remove” the following line from the controller completely.
    – include AuthenticatedSystem

  3. Open up your users_controller.rb file in app → controllers and
    delete all of the code and replace it with the following code:
    code: users_controller.rb · GitHub

  4. Open up your users.rb file in app → models and delete all of the
    code and replace it with the following code:
    code: user.rb · GitHub

  5. Open up your routes.rb file in config and remove all of the code
    and replace it with the following code:
    code: routes.rb · GitHub

  6. Now let’s populate all of the erb mail templates in our app →
    mailers → views → user_mailer with the following files here:
    code: activation.text.html.erb · GitHub

  7. Now let’s open up our user_mailer.rb file under app → mailers and
    remove all of the code and replace it with the following code:
    code: user_mailer.rb · GitHub

  8. Open up your user_observer.rb file under app → observers and
    remove all of the code and replace it with the following code:
    code: user_observer.rb · GitHub

Almost done!

  1. There’s a machinist.rb file that was created in our config →
    initializers folder. Remove this file completely.

  2. In order for observers to work, you need to let rails know that you
    are using them. In your environment.rb file you will add the following
    line:

config.active_record.observers = :user_observer

Here’s the code for our environment.rb file :

  1. Last and finally, run your db migration using rake db:migrate.

As soon as you run the migration, your super user and test user will be
created which will kick off the observer who should mail you your
emails. Check your email. Now then, there’s no need to activate these
particular users because they were already activated for you.


Summary:

I know you are probably anxious to start your rails app up right now and
figure out how it’s all tying in together, but don’t do that. We’ll
cover everything we just accomplished in the next tutorial section as
well as check on our application and learn some extras as well.

TUTORIAL FIVE:

What the heck did I just do?

First, let’s start with running our app and you should see the old
generic starting screen. If you are encountering any errors right about
now then you need to check and make sure you’ve followed this tutorial
completely. Backtrack and if you can’t figure it out, don’t worry you
can ask questions later.

Now, my first inclination is to take you through everything we just did.
However, you can look over all of the code in the controllers at your
own leisure. This tutorial is about mailers and observers so I’m going
to skim a lot here and go into the inner workings of how observers were
used with our user authentication system.

Open up your user.rb model file located in app → models, your
user_observer.rb file located in app → observers, and your
user_mailer.rb file located in app → mailers. Keep them side by side
as we progress onward.

Now then, rather than go into all of the nuances of of your user model
file, I want you to skip down to the section that shows these three
methods:

#used in user_observer
def recently_forgot_password?
@forgotten_password
end

def recently_reset_password?
@reset_password
end

def recently_activated?
@recent_active
end

In the users model file, this is the only section you’ll need to see for
now.

==================================
Understanding Observers

So, first, to understand what an observer does, it’s probably easier to
think of situations in which automation of emails should occur. Let’s
define a quick list of some of them.

When a user signs up on your site
When a user activates their account on your site
When a user forgets their password
When a user resets their password

These are just a few examples where a user does “something” and your
application should respond with an email to the user. Now in the olden
days perhaps administrating users manually would be okay. But, in the
new era, your site could feasibly have thousands of users. That would
end up an administrative nightmare!

Thus God created observers…

Here are the general mechanics of what takes place when a user registers
and signs up on your site:

User clicks on signup/register.
User enters their information but leaves out some validation
requirements.
User hits submit and receives errors and has to fix them before
re-submitting.
User submits the correct information and an account is created.

def after_create(user)
user.reload
UserMailer.deliver_signup_notification(user)
end

After the account is created, our user observer’s after_create method
responds with let’s reload the user (to make sure we have the right user
information) and then we’ll deliver our signup_notification message to
that specific user.

Look in your user_mailer.rb file and you’ll find:

def signup_notification(user)
setup_email(user)
@subject += ‘Please activate your new account.’
@body[:url] =
http://localhost:3000/activate/#{user.activation_code}
end

Notice that in the after_create method it said deliver_ —>
signup_notification(user)

That’s the same thing as saying deliver mail using the
signup_notification method in our user_mailer.

The signup_notification method then performs a setup_email call using
our private setup_email method at the bottom of our user_mailer file and
then has to build the email.

What view can it use to build our email with? How about the
signup_notification.text.(plain/html).erb files in our views →
user_mailer folder. See how the naming convention all matches up?

As you can see, this works out pretty good here. So, what happens next?

Our user receives an email saying click on this link here to activate
your account. Where does it get a link from? How about right from the
user_mailer signup_notification method.

@body[:url] = “http://localhost:3000/activate/#{user.activation_code}

This basically says that anytime the following symbol (url) is used in
the body of the email message, place this string there instead. So, if
you open up your signup_notification.text.plain.erb file you’ll see:

Visit this url to activate your account:
<%=h @url %>

So, the user clicks on the url link and is redirected back to your site
where the activation takes place through your users_controller activate
method. The activation is set true and thus the user has been
recently_activated…

Back in our user_observer, it sees that the user was recently_activated
so what does it do?

UserMailer.deliver_activation(user) if user.recently_activated?

It asks the user mailer to deliver an activation email to the user.

The user_mailer has:

def activation(user)
setup_email(user)
@subject += ‘Your account has been activated!’
@body[:url] = ‘http://localhost:3000/
end

which is the method from deliver_ → activation which was called from
our user observer. And, then which views can it use to format the email
to the user with? That’s right, activation.text.(html/plain).erb.

So, I bet it’s starting to sink in now. If so, pat yourself on the back
for understanding the process.

So, before we go into the summary of this section, let’s quickly do a
sketch of an observer. How about something like a full season sports
subscription. What do you need to get this to work?

Well, you would need an order model that holds the order. (order.rb)
You would need an order observer that watches that model.
(order_observer.rb)
You would need an order mailer that formats and delivers the mail for
that model. (order_mailer.rb)
You would need views that correspond to the delivery methods.
But, wait… why?

It’s probably safe to assume here that your orders are taking place
because your users are purchasing the subscription right? So, there’s
absolutely no need to create an observer. We can simply reuse the
existing one!

So, what if you had something like this:

In your order.rb file you would have to process the order and save the
order. Let’s assume here that you are looking up the user in question:

user = User.find(current_user)

… and then you process the order, adding all of the pertinent
information for the subscription.

Once the order was saved, you could place the following line right
after:

user.fullseason_subscribe

In your user model you place:

def fullseason_subscribe
@fullseason_subscribed = true
end

and …

def recently_fullseason_subscribed?
@fullseason_subscribed
end

In your user_observer you place:

UserMailer.deliver_fullseason_subscription(user) if
user.recently_fullseason_subscribed?

In your user_mailer you would have:

def fullseason_subscription(user)
setup_email(user)
@subject += ‘(Full Season Pass) | Welcome to your full season
subscription!’
@body[:url] = “#{ROOT_SITE_URL}/some_link_to_return_to”
end

And of course the ROOT_SITE_URL could be a constant pointing to your
root url so you wouldn’t have to constantly change the url. You could
add this constant in your environment.rb or place it in the email.rb
file within your initializers…

And, then which views would it use? How about
fullseason_subscription.text.(html/plain).erb. If it’s sinking in,
great!


Summary:

You should now have an understanding of how observers work in terms of
the process. You also should have an understanding of how to create a
new observer and what pieces you need, or that in some areas, you may
want to consoliate your observers specifically to one model if that
model is the appropriate one to use. Let’s do some cleanup in the next
tutorial.

TUTORIAL SIX:

CSS is cool again with mailers

Before I go into this tutorial, one thing I want to remind you from the
previous tutorial is that if you want to activate another observer, say
for another model file, you need to add that observer in your
environment.rb file right after the user_observer.

So, for instance, if you wanted to add an order_observer you would do:

config.active_record.observers = :user_observer, :order_observer, :etc,
:etc,

I just wanted to make this part clear. Now that this is out of the way,
let’s continue on.

Now, if you look at your application which is probably still running,
you are probably saying, man my app looks like garbage. So, let’s give
it a little bit of a look here.

  1. Delete the index.html file in app → public.
  2. Delete the messages.html.erb file in app → views → layouts
    folder.
  3. Create an application.html.erb file in your app → views →
    layouts folder and add the following code:
    code: application.html.erb · GitHub
  4. Create an mailbag.css file in your app → public → stylesheets
    folder and add the following code:
    code: mailbag.css · GitHub
  5. Generate a new controller only called root using:

./script generate controller root index

  1. Open up your routes.rb file and add the following:

| ======== MAIN SITE ROOT ================================ |

map.resources ‘’, :controller => :root, :only => :index
map.root :controller => “root”, :action => ‘index’

  1. Open up index.html.erb in app → views → root and add the
    following:

My Home Page

This is for the mailbag tutorial.

That should get you going. Keep in mind I did not pretty up any of the
views or add graphics to anything. You can play with the CSS if you
don’t like the way it feels. I just provided you with enough to get you
started.

Now then, if you restart your app and go to the main page, you’ll see
your main page and a starting menu that can get you going on testing
your app to see how the contact form works with mailers and observers
work with creating new users. When you’ve finished playing with it,
proceed on.

============================================================
CSS Inside of Mailers

With mailers, all css has to be in-line. This means that you cannot
include an external css file and that the css has to be within the style
tags. However, one nice thing I like to do with my mailers is create a
css partial. I’ll show you how to do this.

In your app → mailers → views → user_mailer folder, create a
partial template named _css_partial.html.erb and place the following
code within it:
code: _css_partial.html.erb · GitHub

So, how would this look now. Let’s do this. Open up all of your
text.html mail template views and place this line right after the

tags:

<%= render :partial => ‘css_partial’ %>

Guess what? You’ve just added in-line css tags to all of your mailer
templates and you can now dress them up easily by doing something like
this:

Your Account Has Been Activated

Check Out Our Services

Sincerely,



The Little Rascals

This allows you to pretty up and beautify your emails with in-line css
and the nice thing is if you can modify the css partial file and leave
the rest of your templates alone.

Your final directory picture should look similar to this one:


Conclusion:

I hope that I’ve provided some information to get you started into using
mailers, and hopefully added a little bit more than that to the
tutorial. If I’ve made a mistake at any point, please don’t hesitate to
let me know.

This tutorial was meant to help those of you who are new to rails and
maybe even provide some added clarity to more seasoned rails veterans
that may approach mailing differently than I do. And, by all means, if
you find something here that can be improved upon, always provide your
input to make it a more solid reference for others.

Take care,

JD (Alpha B.)

Hi Everyone,

I know it’s a long tutorial but I felt I couldn’t make it any shorter.
I tried to post it into parts. Hopefully you’ll find it a good read.
Let me know if you find any issues or errors with it, or if you want to
add your own thoughts to the process for clarification.

Take care everyone.

By the way, the final directory structure image is pointing to the wrong
image. The correct image should be:

My apologies.