How to: Individualized mass email with ActiveMailer - separate thread?

Hi,

We are building a rails application that's sort of a CRM + room/course
booking. Among other things, it provides a centralized database of all
the people the company has been in contact with.

We want to provide the possibility of sending customized email messages
to groups of contacts, for example a newsletter to 500 people starting
with "Hi [:name:]". The naive approach we're using is basically placing
the following code in the controller:

email.people.each do |p|
  # This generates a custom email for that person, with fields such as
[:name:]
  # filled with the person's name
  raw_email = PeopleMailer.create_general_email(email, p, sent_at)
  raw_email.set_content_type("text/html")
  begin
    PeopleMailer.deliver(raw_email)
  rescue Exception => e
    email.log += "\n" + format_time(Time.now) + "\n" + e.message + "\n"
  end
end

The problem is that generating the 500 individual emails takes a
significant amount of time, which causes the browser to time out. What
we want, is to give the user a response immidiately, and then process
the sending of the email in the background.

How to go about this? I've seen the note about mass mailing on
http://wiki.rubyonrails.org/rails/pages/HowToSendEmailsWithActionMailer,
but I couldn't figure out whether it would work in situations where I
want to send a customized email to each recipient.

I tried doing something like

Thread.start do
  # everything as before
end

...but the thread seems to quit as soon as the controller action is
finished rendering, and no emails are sent.

Kind regards,

Erik

You may want to take a look at backgroundrb:

http://groups.google.com/group/rubyonrails-talk/browse_thread/thread/b94003dc7ccc45f6/46a7b29d5e2d5d53

let me know what you find, as I'm doing the same thing right now (with
about 200 users, and I'm doing it the naive way, which works, but I've
been wanting to transition to a background process as well).

Mike

I don't know about running processes in the background, since our
mailing list goes out from a cron job, but we do individualize emails,
mainly for the point of putting in an "Unsubscribe" link for each user.
Also, we found it was best to send the emails in slices of 50. That way
the SMTP Session doesn't get way too big, but it cuts way down on
sending time. Not sure if it's on the script side or the email server
that slows it down(I think it's the email server because it's not
caching the emails but I guess either way they have to sit around for a
short while), but this sends about 6 emails/second. For 500 emails,
that's...just under a minute and a half.

Here's the code:

This is in our main method in the model, Emailer.send_daily_announcements

@users.each_slice(50) do |recipient_group|
   
      # Create an SMTP connection for this group of users
      Net::SMTP.start('smtp.server.here', 25) do |smtp|
     
        # Send the email to each user in this group
        for recipient in recipient_group
                    
          begin
           
            # Output each recipient - TESTING ONLY
            puts "Sending email to: #{recipient.email}"
         
            # Create the email message from our template
            email = Emailer.create_daily_announcement(recipient,
@other_variables)

            # Send out each email
            smtp.sendmail email.encoded, email.from, email.to
         
          rescue Exception => e
            exceptions[recipient] = e
            logger.warn("EXCEPTION: EMAILER.ANNOUNCEMENTS:" + e)
            puts e
           
            smtp.finish
            smtp.start
          end
         
        end
       
      end
     
    end

And our email creation method:

def daily_announcement(user, other_variables)

    # Email header info
    @recipients = user.email
    @from = "us"
    @subject = "Daily Announcements"
    @content_type = "text/html"
   
    @body["user"] = user
    @body["todays_events"] = todays_events
    @body["other_stuff"] = other_stuff

  end

underbjerg wrote: