ActionMailer.deliveries is always an empty array - ruby-on-rails

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.

Related

Rails ActionMailer - Prevent email deliveries for testing

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

Automatically logging email sent through Rails

We send out many emails through Rails (and then through Amazon SES). I'd like to now log all of those emails in our database so we know exactly which emails were sent where and all the details. I'd also love to know which class/method sent those emails or some way to tag them.
This must be an extremely common need, so I'm curious if there's a mechanism with Rails to automatically handle this?
mail-logger gem captures the info about the emails sent, and log them to a file.
With a little bit of work it could be customized to write to a database instead.
The gem is overriding delivered_email method to log the details:
class Mail::Logger::Callback
def self.delivered_email(email)
Mail::Logger.logger.info email.inspect
end
end

Writing a spec for sending a mail via API

I want an E-Mail to be sent using a background process whenever an Invite was generated.
What I currently have is this approach: The Invite model has the method send_mail, which sends an E-Mail using the Mandrill API and gem. It also has the method queue_mail adds InviteMailer with the invite's ID to the queue using Resque.
However… Since I'm having sort of a really hard time writing specs for this, I assume this might not be the best approach to send mails.
What I mainly want and need to test:
was the mail added to the queue?
is InviteMailer working properly?
does the mail contain the correct vital information?
Vital informations are: sent to the correct person, contains a link to a specific site and some specific data/text; also I'm not sure how to get the current host to the link.
I don't think this is a rare thing to do, so I wonder what the best practices are.
My testing environment: rspec, capybara, factory girl. I already added VCR, to cache the API-request.
You can use Mailcatcher to fake your mail server, and check received mail via web API:
Features
Catches all mail and stores it for display.
Shows HTML, Plain Text and Source version of messages, as applicable.
Rewrites HTML enabling display of embedded, inline images/etc and open links in a new window. (currently very basic)
Can send HTML for analysis by Fractal.
Lists attachments and allows separate downloading of parts.
Download original email to view in your native mail client(s).
Command line options to override the default SMTP/HTTP IP and port settings.
Mail appears instantly if your browser supports WebSockets, otherwise updates every thirty seconds.
Growl notifications when you receive a new message.
Runs as a daemon run in the background.
Sendmail-analogue command, catchmail, makes using mailcatcher from PHP a lot easier.
Written super-simply in EventMachine, easy to dig in and change.
How
gem install mailcatcher
mailcatcher
Go to http://localhost:1080/
Send mail through smtp://localhost:1025
API
A fairly RESTful URL schema means you can download a list of messages
in JSON from /messages, each message's metadata with
/messages/:id.json, and then the pertinent parts with
/messages/:id.html and /messages/:id.plain for the default HTML
and plain text version, /messages/:id/:cid for individual
attachments by CID, or the whole message with /messages/:id.source.

Rails Gem or code to have your rails application respond to email and create a record in the database

I am creating a ruby on rails application and I want my users to be able to email the application and have the application take in the email and create a issue record in the database. Is there a GEM or Code that can be used to have the rails application get the email and parse out the body and stick it into an issue table.
I don't know if there is a gem to accomplish the entire task, but you don't technically need one. I recently did this, and though working with ruby's IMAP library isn't the most fun/intuitive thing in the world, it gets the job done.
IMAP can be used to programmatically access and interact with an email account. Here's an example straight from my code (somwhat obfuscated to be easier for someone to implement):
require 'net/imap'
imap = Net::IMAP.new("imap.gmail.com", 993, true)
imap.login(CONFIG["username"], CONFIG["password"])
imap.select('INBOX')
imap.search(["NOT", "DELETED"]).each do |mail_id|
mail = TMail::Mail.parse(imap.fetch(mail_id, "RFC822").first.attr["RFC822"])
do_something_cool(mail)
imap.store(mail_id, "+FLAGS", :Deleted)
end
imap.expunge
imap.logout()
imap.disconnect()
In this example, I'm accessing a gmail account with the IMAP library, going to the inbox, and grabbing each mail that hasn't been deleted. The TMAIL gem, though not necessary, makes dealing with email much easier. In my case, I need to delete emails after I parse them, so I add a delete flag to the email and then, when I'm done, I clear the account of all deleted emails.
The next half is parsing the email for the data you want and making records out of it. I leave that part to the implementor.

View emails sent

I have config.action_mailer.delivery_method = :test and use delayed_job. I run some code that places an email to be sent in a queue, then run rake jobs:work, but nowhere do I see the email that is sent out, and ActionMailer::Base.deliveries is nil. I'm just looking to debug and view the content of htese emails, how can I do so?
When config.action_mailer.delivery_method is set to :test, emails are not actually sent but instead merely added to a list of "sent" messages. That list exists only in memory. That means only the process that "sent" the email can see the list and verify that it was actually "sent".
Since the code that actually sends your mail is being executed in an external process (through a system() or backtick call), your calling script won't be able to see the in-memory queue of that external process and thus won't be able to verify that the emails were actually "sent".
This shouldn't really be a big deal unless something has gone wrong. By default outgoing emails will be written to the log file, so you can verify that they're actually sending by checking there. If you want to view/manipulate the queue in-memory, you'll have to add code to your job to do so, as that is the only code that will have access to it.

Resources