I'm trying to prevent emails from being delivered so I can inspect the contents of ActionMailer::Base.deliveries for testing in a staging environment. I have config.action_mailer.delivery_method = :test in my environment settings but Rails is still attempting to deliver the emails and the deliveries array is empty. What am I doing wrong?
I agree with the other commenter that the best way to prevent all deliveries is through the action_mailer config.
However, if you want an alternative approach that would allow you to redirect any mail, or halt delivery based on a dynamic set of conditions, etc., then I would encourage you to check out Mail Interceptors:
http://guides.rubyonrails.org/action_mailer_basics.html#intercepting-emails
Related
I am using the Postmark gem for rails and writing Rspecs tests to make sure the emails are actually being sent when the form is valid.
I want to check that ActionMailer::Base.deliveries.last.to matches what I put in the contact form I'd like to test.
However, ActionMailer::Base.deliveries is always an empty array. Even in production, after an email is successfully sent (and received on the other end), the array is still empty when observed with rails c production.
What am I missing? How can I verify that the email has been sent in my tests?
ActionMailer::Base.deliveries array is a feature of :test delivery mode provided by ActionMailer (docs). If you’ve enabled Postmark gem in your test environment, that array will always be empty.
Unless you’re aiming for full integration testing, you should avoid using external services in your tests and stick to the :test delivery method. If you do that, you might also want to take a look at the email-spec gem, which provides a DSL for testing emails sent with ActionMailer.
In case you actually want to send emails in your tests, you can use Postmark Messages Retrieval API to retrieve a sent message via recipient or message ID and verify its contents. This allows for complete black-box testing if this is what you’re looking for.
I'm in process of migrating a rails 3.0.11 app to 3.1.3. And somehow, this breaks email_spec testing for amount of emails received when using cucumber + selenium setup.
config.action_mailer.delivery_method = :test, also have tried it with :cache and :file delivery methods. No matter what, ActionMailer::Base.deliveries is empty, even tho according to logs, the emails get sent. And dropping back down to to rails 3.0.11 makes everything work again.
Edit: For specific versions, here is my Gemfile.lock (note that spork is not used for cucumber features).
Clues, anyone?
Try setting:
ActionMailer::Base.delivery_method = :test
ActionMailer::Base.perform_deliveries = true
ActionMailer::Base.deliveries.clear
in your features/support/env.rb or more simply it's a bug somewhere, here we can see people with similar problems: https://github.com/bmabey/email-spec/issues?sort=created&direction=desc&state=open&page=1
Keep an eye out to not send real emails for some reason (bugs, etc.)
delivery_method - Defines a delivery method. Possible values are :smtp (default), :sendmail, :test, and :file. Or you may provide a custom delivery method object eg. MyOwnDeliveryMethodClass.new. See the Mail gem documentation on the interface you need to implement for a custom delivery agent.
perform_deliveries - Determines whether emails are actually sent from Action Mailer when you call .deliver on an mail message or on an Action Mailer method. This is on by default but can be turned off to aid in functional testing.
deliveries - Keeps an array of all the emails sent out through the Action Mailer with delivery_method :test. Most useful for unit and functional testing.
I use ActiveMailer with a 3rd party mailing provider. To develop my app, I want to actually see the emails that come in, as a user would, in my email client.
So in development mode, instead of disabling email, I want my app to send the mails, but change the "to" field so that every email is sent to me. Is that possible?
Update: I want to test the full route my email takes: going through my ESP, arriving in my inbox, viewing it in gmail. I'm not looking to just test that an email is created.
I personally recommend letter_opener by Ryan Bates, however, if you actually want to deliver the mail instead of just viewing it in the browser, there are a number of plugins available that others have already listed. No one, however, has mentioned that you can very easily accomplish this using Interceptors.
Create a new initializer in your config/initializers directory in your Rails app:
# config/initializers/development_mail_interceptor.rb
class DevelopmentMailInterceptor
def self.delivering_email(message)
message.subject = "[#{message.to}] #{message.subject}"
message.to = "YOUR_EMAIL#gmail.com"
end
end
ActionMailer::Base.register_interceptor(DevelopmentMailInterceptor) if Rails.env.development?
This leverages the power of an interceptor on your app. It doesn't configure anything, but rather changes the envelope on the message, altering the to and subject fields. Replace YOUR_EMAIL with the correct value.
The self.delivering_email(message) method is invoked by ActionMailer. You are hooking into that method and override the message envelope.
Finally, you register that interceptor iff we are currently in the development environment.
Be sure to restart your server, and all your mail (in Development) will actually be sent to your email.
Save yourself some trouble and run MailCatcher. MailCatcher is a simple SMTP server that just grabs outbound email and gives it to you in a simple web interface. Install MailCatcher, add this to your environments/development.rb:
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = { :host => 'localhost', :port => 1025 }
Start MailCatcher when you start your Rails server (or use Foreman or something similar to deal with it), and then go to http://localhost:1080/ to see the email that your application is sending out.
You may consider checking out something like MockSMTP (OS X); instead of modifying your "to" fields, you instead set the mail server for dev mode to the "fake" SMTP server created by the app, and from then on ALL emails (sent to anyone) go instead to the app.
I've never used it myself, but I remember seeing that the devs at 37signals use it.
On other operating systems, you may consider one of the following projects:
letter_opener by Ryan Bates - popup a new browser window when an email is sent
MailCatcher (mentioned by mu is too short) - runs a fake SMTP server and a web-based interface for viewing mail sent to it
mailtrap - similar to MockSMTP, has both a mock SMTP server and also a separate viewer program
As much as I like this answer, I went with a different option.
Use the mail_safe gem! As well as providing the functionality from sethvargo's answer, it doesn't require any work other than adding the gem, and it automatically figures out who to email from their .gitconfig.
One important note that I rarely saw mentioned when researching this is that you must use deliver, not deliver!. The latter doesnt call interceptors (though apparently it still calls observers, if that's helpful).
I am using devise and I want to be able to skip the confirmation e-mail while I am in development mode. Since my application can't send e-mail while running on my local machine, I will just get the alert message saying that you need to be confirmed before accessing the application.
Devise has also a method skip_confirmation! that you can call on the model before saving it to avoid sending the mail. It simply sets the confirmed_at attribute which results in skipping the mail sending.
try Letter Opener gem from Ryan Bates
https://github.com/ryanb/letter_opener
it will open the email in the browser without sending it. You don't want to be skipping stuff out if you're in development because stuff will get missed/forgotten about.
As simple as that
user=User.new
user.email="you#email.id"
user.password="yourPassword"
user.skip_confirmation!
user.save
Or you could try MailCatcher in your development environment.
If you want a really light weight way to do this, look in your terminal after registering - the rails output shows the email that got sent, you can copy-paste the confirmation link, confirming the account and then continue testing.
crude, but effective.
In Rails 3 you can use an "interceptor" to reroute your development emails as described in Railscast 206.
Devise uses ActionMailer to send emails. In test mode, ActionMailer shouldn't actually send any emails.
Check out this tutorial for an explanation on ActionMailer and testing environments.
So, depending on the environment, you can basically turn delivery off, while not affecting your actual tests. You just have to specify that option in the environments/test.rb file.
Take your model for devise. Commonly Its user.rb. And remove or comment the config comfirmable.
This will prevent the process of confirmation
simmilar to letter_opener gem (recommended by John Beynon above) there is a gem called mailcatcher which works on SMTP level.
basically you configure SMTP on your Rails app to point to port under which mailcatcher run on local machine and you have mailcatcher browser on other port to read the emails
more info https://github.com/sj26/mailcatcher
The default in Ruby on Rails is to have this set to false (in production and development).
config.action_mailer.raise_delivery_errors = false
Seems strange. I'm definitely turning it on in development which has been helpful. But why does no one seem to have this turned on in production? Shouldn't we want to get notified if an email doesn't go through? This seems rather important.
The rails comment in production.rb states
bad email addresses will be ignored
But I have some validation to check incorrect email addresses. It seems like I'd still want to know (via exception notifier or otherwise) how often users aren't getting emails.
the real question is do you want a failed email to throw an error to your end user? Perhaps the mail server is down or a handful of other reasons prevent the email from being sent. Do you want this to throw a 50x error to your user?
Personally, I deliver all email asynchronously so I can monitor this type of stuff (plus it helps greatly in response times)