So my client has reported that many of the emails are going to the wrong person, and I would like to write some feature tests to find and make sure that they are receiving the email and what it says in my specs.
I have mandrill_mailer which uses mandril api, and before it sends out I would like to see what the message is.
For example. Create a new user account -> creates the user, and then sends out a welcome email. in devise it calls RegistrationMailer.new_registration(resource).deliver
which then sends a email to the user:
def new_registration(user)
user = User.find_by_email(user["email"])
mandrill_mail template: 'new-registration',
subject: 'Welcome to ContentBlvd!',
to: { email: user["email"], name: user["full_name"] },
vars: {
'first_name' => user["full_name"],
'unsubscribe' => "#{CONFIG[:protocol]}#{CONFIG[:host]}/unsubscribe?email=#{user.email}"
}
end
In my mailer how do I test this mail object?
I tried ActionMailer::Base.deliveries, but it returns nil (Since I'm using mandrill mailer...)
So I tried - MandrillMailer::TemplateMailer.message
But no luck.... Thanks for the help.
At this point, MandrillMailer appears to support a robust offline testing set of options. In particular, MandrillMailer.deliveries can now be examined for expectations or debugging purposes.
As per wiki you need to mock Excon
# spec/rails_helper.rb
config.before(:all) do
Excon.defaults[:mock] = true
Excon.stub({}, {body: "{\"html\":\"RESULT\"}", status: 200})
end
You don't have to use the Mandrill gem to send emails using Mandrill. Just use the Rails default Mailer and add the configuration to application.rb or production.rb to use your Mandrill's account.
http://help.mandrill.com/entries/21738467-Using-Mandrill-s-SMTP-integration-with-Web-Frameworks
Related
I am using Sorcery Gem to Authenticate user in my Rails application. Everything is working fine. When user register then I am able to send user activation email. However sending email is taking long time so I was thinking to delay the email or send email in backgroud using Sidekiq. I read Sorcery documentation but couldn't find the way to delay the email using Sidekiq.
Please guide me how to delay the email send by Sorcery gem using Sidekiq.
There could be two approach to this:
Call Sidekiq worker inside Mailer
what I understand from the docs is that you can configure it to call any
Mailer. What you could do inside the method is call
MailerJob.perform_late(*arg) instead of calling mail(*args) right away
Assuming you have a code something like this (ref: https://github.com/Sorcery/sorcery/wiki/User-Activation)
# app/mailers/user_mailer.rb
def activation_needed_email(user)
#user = user
#url = activate_user_url(#user.activation_token)
mail(to: user.email, subject: 'Welcome to My Awesome Site')
end
You can change the code to this
# app/mailers/user_mailer.rb
def activation_needed_email(user)
#user = user
#url = activate_user_url(#user.activation_token)
# mail(to: user.email, subject: 'Welcome to My Awesome Site')
MyMailerWorker.perfor_later(to: user.email, subject: 'Welcome to My Awesome Site')
end
Your worker would be defined as per the sidekiq docs(ref: https://github.com/mperham/sidekiq/wiki/Getting-Started)
class MyMailerWorker
include Sidekiq::Worker
def perform(to: nil, subject: nil)
MailerIWantToCall.send_activation_email(to, subject)
end
end
P.S: Option 1 is not a clean approach but works if you are stuck with Sorcery legacy configs
Don't set mail settings for srcoery(A cleaner approach)
Do not setup mail through sorcery at all.You can revert the changes
mentioned for UserMailer on this page
(github.com/Sorcery/sorcery/wiki/User-Activation) and add a callback on User
model based on when do you want to trigger an email and that way you have
control over what to call and with sidekiq or not.
I found the solution. It's quite easy. We just need to add following line in sorcery.rb file and all sorcery mail will be handled by ActiveJob
user.email_delivery_method = :deliver_later
I use this class for Action Mailer:
class UserMailer < ActionMailer::Base
default from: "something#example.com",
reply_to: 'whatever#example.com'
def mail_method
mail(to: 'email#example.com', subject: "SUBJECT")
end
end
So like this I got many classes and methods which send emails like this from smtp delivery method.
But now I want to perform_deliveries , i.e. send emails only on production environment not in development or test environment.
So for that I want to use my email only, which is why I need to override mail method.
Things I have tried.
-> Making a function to return email, where function name is get_right_email
class UserMailer < ActionMailer::Base
default from: "something#example.com",
reply_to: 'whatever#example.com'
def mail_method
mail(to: get_right_email('email#example.com'), subject: "SUBJECT")
end
end
And definition of get_right_email is as follows:
def get_right_email(email)
if(Rails.env=='production')
return email
else
return 'myPersonalEmail#example.com'
end
end
It would need some refactoring but it is still manageable. Will take a few hours and I can do, but is there a quicker way where I can just override mail function.
In your config > enviroments folder you should have a file for production, development and test. Here you can specify your settings for each one.
Settings in these folders overide those in config > application.rb
For example when testing I don't usually actually send the emails but I do want to be able to test the emails so I use
config.action_mailer.delivery_method = :test
This makes the emails accessible by calling ActionMailer::Base.deliveries
You can set the default from email address in these files as well using:
config.action_mailer.default_options = {
:from => "foo#bar.com"
}
Theres a gem called letter_opener managed by the fantastic Ryan Bates which instead of sending an email in development opens the email in a new tab. This makes testing out emails in development a breeze.
Letter Opener
UPDATE BELOW ------
Apologies, I didn't quite follow what you were looking for.
Rails has webhooks you can use to intercept emails and redirect them. You'll want to use an environment different than production.
The test environment is typically used for automated testing, to keep things clear you might want to consider setting up a new environment (eg: staging).
To create a new environment just create a new file in config/environments/ and give it a suitable name - eg: staging.rb
You can then call Rails.env.staging? where ever you like.
Anyway back to the main event...
To intercept the emails first create an intercept class:
class StagingEmailInterceptor
def self.delivering_email(message)
message.to = ['my#email.com']
end
end
and then create an initializer file, eg:
config/initializers/staging_email_interceptor.rb
and inside do this:
if Rails.env.staging?
ActionMailer::Base.register_interceptor(StagingEmailInterceptor)
end
That way all emails sent in the staging environment will be sent to your email.
This is my mailer:
class MyUserMailer < ActionMailer::Base
default from: "me#mail.com",
:content_transfer_encoding => "7bit"
def build_email(user)
mail(:to => user.email,:subject => "Welcome")
end
end
I'm testing with an address containing umlauts: äardvark#mail.com, but I keep receiving the following error, when I try to deliver the email:
'to' parameter is not a valid address. please check documentation
Documentation says that the mailer will use UTF-8 to encode all the fields. How can I make this work?
EDIT: I'm using Rails 3.2.5
Problem was caused by my usage of the mailgun Rails gem. After I switched to using smtp directly, problem went away.
Is there a gem to do this, and if not, what is the best approach. I'm assuming i'd store the emails in a newsletter database, and would want a form that emails everyone at once. thanks!
No gem for this that I know of.
Actually, due to processing issues, the best way would be to use external bulk email service provider via provider's API.
However, building your own newsletter system is no different from building your regular MVC. Only addition are mailers and mailer views.
(1) So you create model that deals with registration data (:name, :email, :etc...) and model that deals with newsletter itself.
(2) Controller that deals with it (CRUD) + (:send). Send takes each recipient, sends data to mailer which creates email and then sends it.
def send
#newsletter = Newsletter.find(:params['id'])
#recipients = Recipient.all
#recipients.each do |recipient|
Newsletter.newsletter_email(recipient, #newsletter).deliver
end
end
(3) Mailer builds an email, makes some changes in each email if you want to do something like that and returns it to controller action send for delivery.
class Newsletter < ActionMailer::Base
default :from => "my_email#example.com", :content_type => "multipart/mixed"
def newsletter_email(recipient, newsletter)
# these are instance variables for newsletter view
#newsletter = newsletter
#recipient = recipient
mail(:to => recipient.email, :subject => newsletter.subject)
end
end
(4) Ofc, you need mailer views which are just like regular views. Well in multipart there is:
newsletter_email.html.erb (or haml)
newsletter_email.txt.erb
When you want to send both html and text only emails. Instance variables are defined in mailer ofc.
And... that is it. Well you could use delayed job to send them since sending more than several hundred emails can take a while. Several ms times n can be a lot of time.
Have fun.
Please check the maktoub gem there is a blog post over it.
No gem that I know of too and building on #Krule's answer, here's a screencast of setting up mailers in Rails.
How to create, preview and send email from your rails app
I was looking for something similar when I found this. I think with a bit of customization, it can easily be used to create newsletter emails too.
Save money! Spend somewhere else.
I'm wondering if it's possible to configure a Rails email derived from ActionMailer to send to a different recipient based on the environment. For example, for development I'd like it to send mail to my personal email so I don't clog up our company email account with "Testing" emails; for production however I want it to use the real address.
How can I achieve this?
The mail_safe plugin might be a little over kill.
A simple initializer will do
Rails 2.x
if Rails.env == 'development'
class ActionMailer::Base
def create_mail_with_overriding_recipients
mail = create_mail_without_overriding_recipients
mail.to = "mail#example.com"
mail
end
alias_method_chain :create_mail, :overriding_recipients
end
end
Rails 3.x
if Rails.env == 'development'
class OverrideMailReciptient
def self.delivering_email(mail)
mail.to = "mail#example.com"
end
end
ActionMailer::Base.register_interceptor(OverrideMailReciptient)
end
By default the development environment isn't setup to actually send emails (it just logs them).
Setting up alternate accounts can be done in many different ways. You can either use some logic in your mailer like so...
recipients (Rails.env.production? ? "email#company.com" : "test#non-company.org")
Or you can define the recipient as a constant in the environment files like so:
/config/environment/production.rb
EMAIL_RECIPIENT = "email#company.com"
/config/environment/development.rb
EMAIL_RECIPIENT = "test#non-company.org"
and then use the constant in your mailer. example:
recipients EMAIL_RECIPIENT
Also, there are several plugins that do this. The best one that I've found of the three I looked at was mail_safe.