Make a contact form with Mailgun


Alan Vardy
 rails  ruby

Making a contact form can be surprisingly difficult, a number of pieces have to work together to make the magic happen and that is what this post is all about! For this article I am using:

  • Ruby on Rails 5 (The excellent web framework)
  • Mailgun (The email service)
  • Namecheap (DNS)
  • Heroku (Web hosting)

Let’s get started!

Sign up for Mailgun

Make yourself an account at

Specify that you want to use a mg subdomain, so that you will end up using for Mailgun.

Add DNS Settings

Mailgun will not work until they read the proper DNS settings from your provider. For most providers the Mailgun-provided settings will be sufficient, but Namecheap was a whole different ball of wax (lucky me!). I have Namecheap’s “Private Email Service” and have included those settings as well.

Private email:

Hostname Record Type Priority Value
@ MX 10
@ MX 10
@ TXT v=spf1 ~all

Mailgun host records:

Hostname Record Type Value CNAME TXT k=rsa; p=MIGfM… etc

Mailgun mail settings:

Hostname Record Type Priority Value
mg MX 10
mg MX 10

You don’t need the Mailgun Heroku addon

That’s right, I use a config var instead.

Add config vars

Now add that .env file to your .gitignore. This is vital, if you don’t do this then the whole world will have access to your api keys. That is bad.

Set up your gitignore in the main project directory

touch .gitignore
echo '.env' >> .gitignore
git add .
git commit -m 'add env to gitignore'
git push

and add your Mailgun config var to your .env in the main project directory. This allows you to use config variables locally when you run ‘heroku local’. You can alternately install the dotenv gem to load the .env with rails server

touch .env
echo 'mailgun_secret_api_key=XXXXXXXXXXXX' >> .env

And add the same to Heroku so you can use the config var in production

heroku config:set mailgun_secret_api_key=XXXXXXXXXXXX

Add the gem

# Gemfile

gem 'mailgun-ruby'

and install it

bundle install


Create the model

rails generate model Messages --skip-migration

Use this code for the model:

# message.rb

require 'mailgun-ruby'

class Message
  include ActiveModel::Model
  attr_accessor :name, :email, :phone_number, :body
  validates :name, :email, :phone_number, :body, presence: true

  def send
    mg_client = ENV['mailgun_secret_api_key']
    info = {
      from: email,
      to:   '',
      subject: "Email from #{name} -",
      text:    "From: #{name}\nEmail: #{email}\nPhone: #{phone_number}\n\n #{body}"

    mg_client.send_message '', info

Create the controller

rails generate controller Messages new create

Use this code for the controller:

# messages_controller.rb

class MessagesController < ApplicationController
  def new
    @message =
def create
    @message = message_params
if @message.valid?
      redirect_to root_path
      flash[:success] = "I have received your message and will be in touch soon!"
      flash[:warning] = "There was an error sending your message. Please try again."
      render :new
def message_params
    params.require(:message).permit(:name, :email, :phone_number, :body)

and finally the code for new.html.erb

<%= form_for @message, url: messages_create_path do |f| %>
            <div class="form-group">
            <%= f.label :name %>
            <%= f.text_field :name, class: 'form-control'%>

            <div class="form-group">
            <%= f.label :email %>
            <%= f.email_field :email, class: 'form-control'%>

            <div class="form-group">
            <%= f.label :phone_number %>
            <%= f.telephone_field :phone_number, class: 'form-control'%>

            <div class="form-group">
            <%= f.label :body %>
            <%= f.text_area :body, class: 'form-control', rows: '5'%>

            <div class="form-group">
            <%= f.submit 'Send Form', class: 'btn btn-outline-primary'%>
        <% end %>

Start up your local server

heroku local
# or rails server if you installed the dotenv gem

And let me know if you have any issues!

Like what you see?

Related Posts