Implementing Dynamic Email Settings in Rails

TL;DR: The easiest possible way to configure email server dynamically in your Rails app.

Swaathi Kakarla
Sudo vs Root

--

Rails supports mailing out of the box with Action Mailer. It’s so easy to setup mail settings and design your email. But one disadvantage we faced was when allowing admins to change their email settings without having to restart the entire application. In many ways this is an advantage to applications, but we needed a but more flexibility. And maybe you do too!

If you’re not sure about setting up email, you can check out this post. It’s very well written and will get you started.

Let’s generate a mailer which extends the ApplicationMailer class,

rails generate mailer UserMailer

This will generate a mailer called user_mailer.rb file in your mailer folder of the app directory in your Rails application. It will probably look like this,

class UserMailer < ApplicationMailer 
end

You can define functions inside this class to send various mails. You could have one for a Welcome mail, a Test mail, anything.

def welcome_email(user)@user = user@url = `http://example.com/login`mail(to: @user.email, subject: `Welcome to My Awesome Site`)end

And these instance variables will be available to your mailer views, which is just a HTML-ERB file in your app/views/user_mailer directory. Simple as that! It might look something like this,

<!DOCTYPE html><html><head><meta content=`text/html`; charset=`UTF-8` http-equiv=`Content-Type` /></head><body><h1>Welcome to example.com, <%= @user.name %></h1><p>You have successfully signed up to example.com, your username is: <%= @user.login %>.<br></p><p>To login to the site, just follow this link: <%= @url %>.</p><p>Thanks for joining and have a great day!</p></body></html>

To deliver your email, you just have to call the welcome_email function.

UserMailer.welcome_email(@user).deliver_now

Now, for the emails settings.

The traditional way is to setup your email would be to store them in your config/environments/$RAILS_ENV.rb file ($RAILS_ENV) is a constant which will return the environment your app is currently running in — developement, test, or production).

A sample setting for gmail could be,

config.action_mailer.delivery_method = :smtpconfig.action_mailer.smtp_settings = {address: ‘smtp.gmail.com’,port: 587,domain: ‘example.com’,user_name: ‘<username>’,password: ‘<password>’,authentication: ‘plain’,enable_starttls_auto: true }

This would restrict your app to be able to send emails from only these static settings. If you need to send it from another email account, you’d need to edit this file and restart your application.

Another way out of this, is to have your settings local and available for only that mailer class. This would be useful if you know your various email settings and selectively choose from which email account you want to send the email from. This works out in mose cases.

class UserMailer < ApplicationMailerself.smtp_settings = {:address => ‘smtp.gmail.com’, :port => 587,:domain => ‘gmail.com’,:authentication => ‘plain’,:user_name => <email_username>,:password => <email_password>,:enable_starttls_auto => true}def welcome_email(user)@user = user@url = `http://example.com/login`mail(to: @user.email, subject: `Welcome to My Awesome Site`)endend

This way you can setup multiple mailer classes each with it’s own individual email settings. This provides you with a decent level of flexibility, however you would need to know your email settings and the number of email accounts before hand. It might be a requirement for your application.

However, with ours we needed to allow the admin to be able to set his email settings, change it whenever he needs to, and send all emails from that mail settings only.

To allow the admin to store his settings we used a gem called Settings Logic. This gem allowed us to specify a YML file and access the attributes in the file with simple objects in the Rails application. It was straight forward and useful.

We created a YML file called “Email” and allowed the admin to add his email settings here. We also allowed him to edit the YML file to his/her wish (via a simple form setup to interact with the YML file).

Here’s how it looked, config/email.yml

email_address: smtp.gmail.com 
email_port: 587
email_domain: gmail.com
email_username: example@gmail.com
email_password: example

With the Settings Logic gem, accessing these attributes is as easy as “Email.email_address”.

Back to our UserMailer class,

class UserMailer < ApplicationMailer 
# Setting default option as 2 incase option parameter is empty def send_mail(option = 2, data)
if option == 1
email = UserMailer.welcome_mail(data)
elsif option == 2
email = UserMailer.test_mail(data)
end
email.delivery_method.settings.merge!({:address => Email.email_address, :port => Email.email_port, :domain => Email.email_domain, :user_name =>Email.email_username, :password => Email.email_password, :enable_starttls_auto => true}) email.deliver_now end def welcome_email(user)
@user = user
@url = ‘http://example.com/login'
end
def test_email(user)
@user = user
end
end

What we do here is call upon an object of the UserMailer class, set the email settings and deliver the email. This is safer and more reusable than creating different classess for different email settings. It also allows you to change the email settings on the run.

In order to deliver the email, it’s as simple as calling the send_mail function and passing the required data.

Inbox.send_mail(1, user).deliver_now

There you have it! Dynamic email settings, the easy way.

Originally published at blog.skcript.com.

--

--

Swaathi Kakarla
Sudo vs Root

Co-Founder and CTO @SkcriptHQ | Loves to code | GDG-CHN Organizer | https://swaathi.com