Mailboxer Demo App Now Available

I wrote a tutorial last year that explained how to customize the Mailboxer Ruby gem and it was well-received. Many people requested source code so that they could debug issues. I unfortunately did not have the availability to provide the source code at the time. However, I am very happy to announce that an open source application is currently available on Github and it is completely free to use. A live demo of the app is also available on Heroku. I hope this helps anyone that is struggling to get mailboxer up and running in their Rails app! As always, feel free to ask questions if you run into issues.

Customizing the Mailboxer Ruby Gem

Update 3/1/2015: This tutorial has been updated for Rails 4.2 and Mailboxer 0.12. I also created a demo application that can be found on Github. A live demo of the app is also available on Heroku.

The Mailboxer Ruby gem is a robust messaging system that is extremely easy to implement in any Rails app. There are some good tutorials out there that explain how to quickly get it up and running but I saw many questions that asked how to customize the inbox. In this blog post I will explain how to set up the Mailboxer gem and customize the views to contain the following:

  • Inbox with Sender, Subject, Date, and link to move to Trash
  • Trash with the same information as Inbox as well as a button to delete all conversations in Trash and a button to move a conversation back to the Inbox
  • Conversation view page showing all associated messages and a reply form

You’ll see the words “conversation” and “message” used throughout this blog post. In Mailboxer a conversation is simply a group of messages. Our Inbox and Trash pages will contain a table of conversations. Clicking on a conversation will open all of the messages associated with that conversation.

Note: I will be using the current_user method to refer to the currently logged in user. This method is supplied by the Devise gem. If you are not using Devise to handle user authentication be sure to replace this method with your own.

Much of this code for the Conversations controller was provided by RKushnir’s Mailboxer sample app on Github. You can see the full controller code here (since this is a private messaging system between two users, the create action in the linked controller is not needed).


Add the following line to your Gemfile:

gem "mailboxer"

Then run:

bundle update

Next, run the install script. This script will automatically create the migrations that are required for Mailboxer to run:

rails g mailboxer:install

Migrate your database once the installation is complete:

rake db:migrate

Prepare the models

Mailboxer can be used on any model but in this example we’ll prepare our User model to use Mailboxer. Add the following line to your User model:

User > ActiveRecord::Base

Basic Mailboxer view

To create some test messages use the following method in the Rails console or set up a form in a view (replace “recipient_user_object” with a real User object from your app):

current_user.send_message(recipient_user_object, "body", "subject")

The quickest way to show the contents of your Inbox is to add the following line of code in your view:

<%= render current_user.mailbox.inbox %>
If you aren’t using Devise you can substitute current_user with any User object.
As you can see the output is pretty basic if we simply render the inbox using the above code. A bullet list is generated with the conversation subject and a “Move to Trash” link for each conversation.

Edit the Conversations controller

Before we edit our views we’ll need to add some code  to our Conversations controller. Add a conversations instance variable to our index action which will contain all of the user’s inbox messages:
class ConversationsController > ApplicationController
  before_filter :authenticate_user!
  helper_method :mailbox, :conversation
  def index
    @conversations = @mailbox.inbox.all

Create a reply action which will be called when replying to a message within a conversation:

def reply
 current_user.reply_to_conversation(conversation, params[:body])
 redirect_to conversation_path(@conversation)

Create a trash_folder action in your Conversations controller and add an instance variable which will contain all of the user’s messages in the Trash folder:

 def trashbin     
  @trash ||= current_user.mailbox.trash.all   

The above actions will handle our Inbox and Trash pages. However, we’ll also need to add actions for the Trash and Untrash actions. We will be adding a link on the Inbox page to allow the user to send a conversation to the Trash folder. We’ll also add an “Untrash” link on the Trash page to send a conversation back to the Inbox page. To do this, create the trash and untrash actions in the Conversations controller:

def trash
 redirect_to :conversations
def untrash
 redirect_to :back

Add an emtpy_trash action to the Conversations controller:

def empty_trash
  current_user.mailbox.trash.each do |conversation|
   conversation.receipts_for(current_user).update_all(:deleted => true)
 redirect_to :conversations

You’ll also need to add the following private methods called by the other methods mentioned above. They define @mailbox and @conversation:


def mailbox
 @mailbox ||= current_user.mailbox

def conversation
 @conversation ||= mailbox.conversations.find(params[:id])

Edit the Messages controller

We’ll need to add two actions to our Messages controller: new and create. These actions will be used to send a new message to a user, thus starting a new conversation:

class MessagesController > ApplicationController

  # GET /message/new
  def new
    @user = User.find(params[:user])
    @message =

   # POST /message/create
  def create
    @recipient = User.find(params[:user])
    current_user.send_message(@recipient, params[:body], params[:subject])
    flash[:notice] = "Message has been sent!"
    redirect_to :conversations

Customize the views

Mailboxer keeps track of the participants in a conversation. In our case, the only participants are the sender and the recipient. To show the sender of a message, loop through all of the participants and only show participants except for current_user:

<% @conversations.each do |conversation| %>
  <% if participant != current_user %>
    <%= %>
  <% end %>
 <% end %>

Conversation.subject can be used to display the conversation’s subject. You can have it link to the full conversation with this:

<%= link_to conversation.subject, conversation_path(conversation) %>

To show the date it was sent, you can use conversation.created_at. In the code below I’ll use update_at since conversations may last longer than a day. I’ll also use strftime to format the date into the “Sun, 01/01/2014 12:00 PM” format:

<%= conversation.updated_at.strftime("%a, %m/%e/%Y %I:%M %p") %>

Now for the Trash link. This link will call the trash action we setup in the controller above:

<%= link_to "Move to Trash", {:controller => "conversations", :action => "trash", :id =>}, :title=> "Move to Trash", :method=> 'post' %>

In the next section we’ll need to setup the routes so that the Trash links will work correctly. Before we move on to the routes we’ll need to customize the Trash page. The Trash page is going to be the same as above except for two things:

1. When looping through the participants to display the sender, change the first line to this:

<% @trash.each do |conversation| %>

2. Change the Trash link to an “untrash” link. Clicking on this link will send the conversation back to the Inbox:

<%= link_to "Move to Inbox", {:controller => "conversations", :action => "untrash", :id =>}, :title => "Move to Inbox", :method=>'post' %> 

Create a show.html.erb view page for a single Conversation. You’ll also want to include a messages form that allows the user to reply to a message within a conversation (we’ll create the form next):

<%= conversation.subject %>

A conversation with
<% @conversation.participants.each do |participant| %>
 <% if participant != current_user %>
  <%= %>
 <% end %>
<% end %>
<%= content_tag_for(:li, @conversation.receipts_for(current_user)) do |receipt| %>
 <% message = receipt.message %>
 <%= %>
 <%= simple_format h message.body %>
 Sent <%= time_ago_in_words(message.updated_at) %> ago

<% end %>

<%= render 'messages/form', conversation: @conversation %>

The messages form, named _form.html.erb in the Messages views folder, is a simple form that looks like this:

  <%= form_tag reply_conversation_path(conversation), method: :post do %>
 <%= text_area_tag 'body', nil, cols: 2, class: 'form-control', placeholder: 'Type your message here!', required: true %>
 <%= submit_tag "Send Message", class: 'btn btn-primary' %>
 <% end %>

Lastly, create a new message form that will be used to send a new message to a user and start a new conversation. Name this page new.html.erb within the messages view folder:

Send a message to <%= %>

<%= form_tag({controller: "messages", action: "create"}, method: :post) do %>
 <%= label_tag :subject %>
 <%= text_field_tag :subject %>
 <%= label :body, "Message text" %>
 <%= text_area_tag :body %>
 <%= hidden_field_tag(:user, "#{}") %>
 <%= submit_tag 'Send message', class: "btn btn-primary" %>
<% end %>

We’re almost there! The last thing we need to do is update the routes file.

Updating the routes

Add this to your routes:

resources :messages do
  member do
    post :new
resources :conversations do
  member do
    post :reply
    post :trash
    post :untrash
 collection do
    get :trashbin
    post :empty_trash

And that’s it! Please let me know if you have any questions.