Send to multiple recipients in Rails with ActionMailer

55,274

Solution 1

I have the same problem. I don't know what is the deal is. I sidestep it by:

instead of calling

Mailer.request_replacement(shift).deliver 

from my controller,

I'd define a class method on the mailer, and call that. That method would then iterate through the list and call deliver "n" times. That seems to work:

class Mailer

   def self.send_replacement_request(shift)
     @recipients = ...
     @recipients.each do |recipient|
       request_replacement(recipient, shift).deliver
     end
   end

   def request_replacement(recipient, shift)
     ...
     mail(...)
   end
end

and from the controller, call

Mailer.send_replacement_request(shift)

Solution 2

You can just send one email for multiple recipients like this.

def request_replacement(shift)
  @shift = shift
  @user = shift.user
  @recipients = User.where(:replacement_emails => true)
  @url  = root_url
  emails = @recipients.collect(&:email).join(",")
  mail(:to => emails, :subject => "A replacement clerk has been requested")
end

This will take all your @recipients email addresses and join them with ,. I think you can also pass an array to the :to key but not sure.

The only problem is you won't be able to use @name in your template. :(

Solution 3

In the Rails guides (Action Mailer Basics) it says the following regarding multiple emails:

The list of emails can be an array of email addresses or a single string with the addresses separated by commas.

So both "[email protected], [email protected]" and ["[email protected]", "[email protected]"] should work.

See more at: http://guides.rubyonrails.org/action_mailer_basics.html

Solution 4

To prevent each recipient from seeing the other email addresses:

@recipients.each{ |recipient| Mailer.request_replacement(recipient, shift).deliver }

Solution 5

I'm using Rails 5 and I have the same situation, the email was sent only to the last recipient but also it was sent just as plain text not as HTML email.

After trying some advices, I ended up fixing it in this way:

The mailer:

class BrochureMailer < ApplicationMailer
    default from: "[email protected]"

    def newsletter(sponsor, brochures_list)
        @sponsor = sponsor
        @brochures = brochures_list

        mail(
            to: @sponsor.email,
            subject: "Interesting subject!"
        )
    end
end

The controller where the mailer is invoked:

class Admin::DashboardController < Admin::BaseController
    def send_newsletter
        sponsors = params[:sponsor_ids]
        brochures = params[:brochure_ids]

        sponsors = Sponsor.where(id: sponsors)
        brochures = Brochure.where(id: brochures).to_a

        # Send Newsletter email to the given Sponsors
        sponsors.each do |sponsor|
            BrochureMailer.newsletter(sponsor, brochures).deliver_later
        end

        redirect_back(fallback_location: admin_root_path, success: 'Newsletter sent!')
    end
end

And in the view, something like this:

<% @brochures.each do |brochure| %>
    <table width="280" border="0" cellpadding="0" cellspacing="0" align="left" valign="top" class="floater">
        <tr>
            <td align="center" valign="top">
                <a target="_blank" href="<%= brochure_url(brochure) %>">
                    <img border="0" vspace="0" hspace="0" src="<%= brochure.image.blank? ? 'default.png' : brochure.image.url(public: true) %>" width="250" height="142">
                    <b><%= brochure.title %></b>
                </a>
                <br>
                <%= brochure.description.truncate(60) %>
            </td>
        </tr>
    </table>
<% end %>

And it works like a charm! I'm not sure if this is the correct way or the most optimal way to go but just consider it as a second possibility.

I hope it could be useful for somebody else.

Share:
55,274
Slick23
Author by

Slick23

Updated on July 09, 2022

Comments

  • Slick23
    Slick23 almost 2 years

    I'm trying to send multiple emails based on a boolean value in my database. The app is a simple scheduling app and user can mark their shift as "replacement_needed" and this should send out emails to all the users who've requested to receive these emails. Trouble is, it only every seems to send to one email. Here's my current code:

     def request_replacement(shift)
          @shift = shift
          @user = shift.user
          @recipients = User.where(:replacement_emails => true).all
          @url  = root_url
          @recipients.each do |r|
            @name = r.fname
            mail(:to => r.email,
               :subject => "A replacement clerk has been requested")
          end
      end
    
  • Slick23
    Slick23 over 12 years
    Yeah, but I really don't want to expose the email addresses of every user ... I think I found a solution by moving the .each block in to the model and calling deliver from there.
  • Chris Ledet
    Chris Ledet over 12 years
    True, if that's the case. You can use bcc field.
  • Marc Talbot
    Marc Talbot almost 12 years
    FWIW, this doesn't seem to work on Amazon SES, where they are expecting commas as the delimiters (though it works when you use comma instead of semicolon).
  • Urkle
    Urkle over 11 years
    Comma is the correct delimiter, not a semicolon. AFAIK only Outlook uses semicon, and it translates it to commas when it generates the final email.
  • turboladen
    turboladen about 11 years
    I don't think I would've ever figured that out. Thank you!
  • kamal
    kamal over 8 years
    If you don't call deliver method in controller it does not even go inside mailer method.
  • cgenco
    cgenco over 7 years
    You could also add them as bcc, like this: mail(:to =>"[email protected]", :subject => "A replacement clerk has been requested", :bcc => @recipients.map(&:email).join(","))
  • Veck Hsiao
    Veck Hsiao almost 7 years
    bcc is a way to reach don't want to expose the email addresses of every user, but since this will hide receivers' address, many mail services will detect the mail as a spam.
  • TheRealMrCrowley
    TheRealMrCrowley over 6 years
    I just want to point out that the join in your comment is not needed. action mailer can take arrays of emails
  • Toshe
    Toshe over 3 years
    This is the best solution and it links to the official documentation. If you want to hide the recipients use bcc.