Cyril Duchon-Doris
Cyril Duchon-Doris

Reputation: 13929

Rails email preview for users in production

Context

Gems like mail_view, mailcatcher, rails_email_preview, etc. seem to be more developer-oriented (a way to debug a template). But I need something that will be used by the trusted users of my rails app in production.

My app is a project management app, where project managers can update the status of their projects, operations during which emails must be sent to project contractors, developers, clients, etc.

The project manager must be able to tell whether or not he wants to send an email (this is easy), and be able to customize to some extent the message content (not the design, only specific text parts should be enough). They DO want to have some control over the email about to be sent, ie, they need a preview of the email they customized. Why ?

  1. Project Managers are trusted users/programmers, and I let them add HTML as custom parts of the email (We are talking about a small-scale app, and the project managers are all trusted employees). But a closing tag is easily forgotten, so I want to provide them with a mean to check that nothing is wrong. Eg. that the text does not all appear as <h2> just because they forgot a closing </h2>
  2. Some email templates already include some info about what the PM is writing about, and the PM may not be aware of it (understand : may be too drunk to remember it). An email preview is just a way to avoid duplicate sentences (like two times Hello M. President,)
  3. CSS styles are applied to the email. It can be hard to anticipate the effect of tags like <h2>, etc. So I need to render the email with the CSS

REMARKS

Previsualize & Send button

Project managers have access to a form that will feed the content to my Rails app. I am thinking on having both a normal submit button, and a previsualize button. I will probably use some tricks given by this SO question to differentiate the behaviours of the 2 buttons

Letter_opener : a nice gem, but exclusive ?

I am using letter_opener for debug (so different context), but this is typically the preview I'd like to show to the project manager. However, in order to be used, letter_opener requires to modify action_mailer configuration config.action_mailer.delivery_method = :sendmail # (or :letter_opener). So I can only previews emails, or send them for real, not both ? I would accept a solution that would let me choose whether to use letter_opener or send the email for real

Small Editor ?

Instead of blindly trusting my project managers' ability to write basic html without forgetting closing tag, maybe you could recommend a nice WYSIWYG editor that would show the content of my f.text_area() ? This would be a bonus, not an actual answer to my question

Email rendering engine ?

I am now aware that different email clients can render the email client differently. I will ignore this for now. So the way the preview is rendered doesn't matter. I like the rendering of letter_opener however

Current Code

View > Controller > Mailer

my_email_view.html.erb

<%= form_tag some_mailing_list_path %>
  <%= fields_for :email do |f| %>
  <!-- f.text_field(:subject, ....), etc -->
  <% end %>

  <%= submit_tag("Send email") %>
  <%= submit_tag("Preview") %>
<% end %>

my_controller.rb

before_action :prep_email # Strong parameters, define @mail with form contents

# Handles the POST 
def some_action
  check(:to, :from, :subject) # I check the parameters in private functions
  if email_alright? # Above checks will raise a flag if something went wrong
      if Rails.env.production?
        MailingListsMailer.my_action(@mail).deliver_later
      else
        MailingListsMailer.my_action(@mail).deliver_now
      end
      flash.notice = "Email sent"
      redirect_to :back
    else
      redirect_to :back
    end
end

mailing_list_mailer.rb

def my_action(message)
    format_mail_params(message) # Will set more variables
    @etude = etude
    @include_reference = message[:include_reference]
    @include_description = message[:include_description]
    dst = Proc.new { read_emails_file }
    mail(
      to: dst,
      from: message[:from],
      subject: @subject_full)
  end

Upvotes: 1

Views: 855

Answers (2)

Ryan.lay
Ryan.lay

Reputation: 1761

Question update: based on your pseudocode, this is a simple case of creating a status update model and emailing the update to a mailing list.

There are several ways you can go about it, but I'd suggest that you keep things simple and avoid using gems.

<%= link_to "New update", new_status_update_path, class: 'button' %>

Model

class StatusUpdate
  belongs_to :sender, class_name: 'User'
  belongs_to :mailing_list
end

Controller

class StatusUpdateController
   def new
      @status_update = StatusUpdate.new
   end

   def create
      @status_update = StatusUpdate.create(status_update_params)
      @status_update.mailing_list = MailingList.where(whichever_mailing_list)
      if @status_update.save
        redirect_to :action => "preview", :status_update => @status_update
      end
   end

   def preview
     @status_update = StatusUpdate.where(id: params[:id]).first
     @mailing_list = MailingList.where(id: @status_update.mailing_list_id)
   end

   def send
      @status_update = StatusUpdate.where(id:params[:status_update_id]).first
      Mailer.status_update_email(@status_update).deliver
   end
end

status_updates/new.html.erb

<%= simple_form_for(@status_update) do |f| %>    
    <%= f.input :title %> 
    <%= f.input :content, as: :text %>
    <%= f.button :submit, 'Post update' %>
<% end %>

status_updates/preview.html.erb

<h1>Preview</h1>
<%= simple_form_for(@status_update, :url => url_for(:controller => 'StatusUpdateController, :action => 'send') do |f| %>

    <%= f.input :subject %>

    <div class="email-render-container">
      <%= @status_update.content %>
    </div>

    <p>Make changes</p>
    <%= f.input :content, as: :text %>

    <%= f.button :submit, 'Approve and send emails' %>
<% end %>

If I were you, I'd do away with the preview feature. If you're loading content from a template and all you're worried about are potential duplicate content, just do this:

Controller

class StatusUpdateController
  def new
      @status_update = StatusUpdate.new
      template = UpdateTemplate.where(however_you_assign_the_template)
      @status_update.content = template.content
  end

  def create
      @status_update = StatusUpdate.create(status_update_params)
      @status_update.mailing_list = MailingList.where(whichever_mailing_list)
      if @status_update.save
        Mailer.status_update_email(@status_update).deliver
      end
   end
end

and style the new status update form with css to simulate writing on the actual email template. You'll save your users and yourself a lot of time.


wysiwyg editor

Never trust the end user with the ability to write html. Depending on your needs, I find https://www.froala.com/wysiwyg-editor easy to deploy.

differentiating buttons

Just use a preview icon with a label on your button and/or a subtitle under your button to differentiate your buttons. You don't need much command logic in your view.

Alternatively, if you think that the preview is important to your end users, just use the "preview" button as the next logical step instead of presenting your users with too many unnecessary choices.

Suggestions

Adopting a front end framework like Angularjs makes this sort of use case almost trivially easy, but it may be overkill and comes with steep learning curve if you're not familiar with it.

Upvotes: 1

Eric Remer
Eric Remer

Reputation: 11

Take a look at letter_opener gem. It was created by Ryan Bates, the Railscasts guy.

Upvotes: 0

Related Questions