How to cache a mailer view when sending massive email - ruby-on-rails

I need to send massive email,I will use for brackground job Delayed Job, and have to create the email message in 3 languages (de, en, re), How can I cache the view so it doesn't have to create each time I'm calling the the mail method.

The deliver method is the one that sends the email, so you can do this:
def send_emails
# You can set here the email with attachments and all stuff
mail = MyMailer.send_message("demo#example.com")
body = mail.html_part.body
User.all.each do |u|
mail.to = u.email
mail.html_part.body = body.gsub(/user_id/, u.id)
mail.deliver
end
end
Of course it's better if you set this method for background processing.

Related

Pass job results to other job with Sidekiq

I make an API call to fetch an email address. On success I'd like to pass this email address to another job. I use sidekiq and sidekiq-batch gems.
class HandleWebhookJob
def perform
batch = Sidekiq::Batch.new
batch.description = "Handling webhook"
batch.on(:success, HandleWebhookJob::OtherJob, { email: #email })
batch.jobs do
#email = GetEmailJob.perform_async # returns email address
end
end
class OtherJob
def on_success(status, options)
puts options # no email address here - nil
# need to pass it to UseEmailJob.perfom_async(options[:email])
end
end
end
I assume that assigning the result of GetEmailJob to #email won't work. Can't find an example of how to do this and if it's even possible.
I think that you get jid in #email.
Can you save emails in GetEmailJob to some storage (e.g. redis) with prefix:jid key and take them from there?

Rails Action_Mailer

I am using admin mailer in my Rails 4 app.
I have two emails to send out upon registration. One is to me and the other is to the user. They are supposed to send from different email addresses, each of which is specified in the from field in the mailer method (as set out below). The problem is they are both being sent from the email address specified as the sender in the first method.
My mailer methods are:
def new_user_waiting_for_approval(user)
#user = user
mail(to: "aa#gmail.com", from: "bb#gmail.com",
subject: "Registration Request #{user.first_name} #{user.last_name} <#{user.email}>")
end
def new_user_waiting_for_access(user)
#user = user
mail(to: user.email, from: "cc#gmail.com", subject: "Welcome, #{user.first_name}")
end
Inside my Admin_Mailer class, I have a default 'from:' email address above the method which is specified as the sender in the first of the above methods. This might be overriding the from specified in the method itself.
Does anyone know how to specify different senders in separate methods so that my emails send from the appropriate email address?
Thank you
If you couldn't figure it out by changing the configs you can use the code given below.
Add this code snippet to your code base.
class Emailer < ActionMailer::Base
def activation_instructions(recipients_emails, sender = nil, mail_subject = nil, text = "")
subject mail_subject || "Default subject"
recipients recipients_emails
from sender || "default_mail_id#abc.com"
sent_on Time.now
content_type "text/html"
body text
end
end
And you can send the mail by calling the above defined method as follows.
Emailer.deliver_activation_instructions("recient#abc.com", "sender#abc.com", "Subject", "content")

ActionMailer send email in background, queue_classic

I am using queue_classic,
How can I send the following email using queue_classic?
Notifier.welcome(david).deliver # sends the email
UPDATE
I have added a new class method into User class
def.say_hello
puts "hello!"
Notifier.welcome(#david).deliver
end
QC.enqueue("puts", "hello world") works fine,
but QC.enqueue("User.say_hello") doesn't send email"
What could I do?
It looks like queue_classic's enqueue method takes two arguments:
method to call
arguments to pass to this method
So you need to write a method that you can call with the two items above that will deliver your email.
module QueueNotifier
def self.send_welcome_email_to_user(id)
user = User.find(id)
Notifier.welcome(user).deliver
end
end
Then in order to enqueue these sending events, you would queue up the method name (QueueNotifier.send_email_to_user) and the argument (whatever the user id of david or the user you want to send to).
QC.enqueue("QueueNotifier.send_welcome_email_to_user", 14)

DelayedJob email where to have 'who to email' logic

In my app I have certain events that trigger a lot of emails (~100). Obviously sending them immediately is not an option, so I'm using DelayedJob to queue them up and send them after the request is processed. I've now found that the logic to determine WHICH 100 people to email is heavy enough that it takes a while to run, so I'd like to DelayedJob that process as well. Where should this logic go? (model? mailer?) Sending mail from the model just feels wrong. Is there a best practice here?
You should write a class that represents the job. Not a model class, not a controller class: a job class.
# app/jobs/mail_job.rb
class MailJob
attr_accessor :first_option, :second_option
def initialize(first_option, second_option)
self.first_option = first_option
self.second_option = second_option
end
def perform
accounts = Account.where("some_key" => first_option).to_a
# more complicated stuff goes here
accounts.each do |account|
AccountMailer.hello_message(account).deliver
account.mark_hello_delivered!
end
end
end
job = MailJob.new(params["first"], params["second"])
Delayed::Job.enqueue(job)

ActionMailer execution timeout

When trying to send an email to the user for reseting their password, I keep getting an execution timed out error. Other mailer functions work, so I know that the config settings are correct. The header reads: "Timeout::Error in Password resetsController#create"
Here is the password_resets_controller:
def create
#user = User.find_by_email(params[:email])
if #user
User.deliver_password_reset_instructions(#user.id)
flash[:notice] = "Instructions to reset your password have been emailed to you. " +
"Please check your email."
redirect_to '/'
else
flash[:notice] = "No user was found with that email address"
render :action => :new
end
end
Here is the method inside of User.rb
def self.deliver_password_reset_instructions(user_id)
user = User.find(user_id)
user.reset_perishable_token!
Emailer.deliver_password_reset_instructions(user)
end
Finally, here is the actual method inside of emailer.rb:
default_url_options[:host] = "http://0.0.0.0:3000" #development
def password_reset_instructions(user)
#subject = "Application Password Reset"
#from = 'Notice#myApp.com'
#recipients = user.email
#sent_on = Time.now
#body["edit_password_reset_url"] = edit_password_reset_url(user.perishable_token)
#headers["X-SMTPAPI"] = "{\"category\" : \"Password Recovery\"}"#send grid category header
end
Why is "Password" in the error message referred to causing a timeout::error
Sending email (or other long running processes) from the main controller request thread is not a good idea. The sending of the email can time out for a variety of reasons that are not under your control (e.g. the outbound email delivery server being down) and you don't want your application server and users to suffer due to that.
A better approach is to use a queuing mechanism like Delayed Job (DJ) to queue these email tasks, and have them be processed outside of your controller threads.
See https://github.com/collectiveidea/delayed_job
Integration of this (or another queuing system) into your rails app is fairly simple. And rails 4 is said to have built in queuing services (which I'm yet to use) http://blog.remarkablelabs.com/2012/12/asynchronous-action-mailer-rails-4-countdown-to-2013.
For instance, if you use DJ in your app, the new code will look like below
def self.deliver_password_reset_instructions(user_id)
user = User.find(user_id)
user.reset_perishable_token!
# this is the only line that changes
Emailer.delay.deliver_password_reset_instructions(user)
end
The jobs are stored in the database, and re-tried when errors like time outs happen.
You can read more about DJ on the github page.

Resources