Nov 2020
Be Careful what you tell your computers to do, because they’ll do it.
I’m making a web app using Rails, and the gem Faker allows us to work with dummy user data before actual non-dummies Log On.
I was using the Harry Potter flavor of Faker’s dummy data, so my users had names like Fluffle BippleBap and emails like fbibblebap@gmail.com.
When a user creates an account, she gets a welcome email. Rails ActionMailer makes this nice and easy.
Since we’re in Rails Land, of course we’re using Devise - this allows us to create and manage user accounts with ease.
Controllers and Models
Since we’ve outsourced our account creation to Devise, we don’t have immediate access to a create
action in the users_controller
- Devise has it’s own controllers.
But we want to send a user an email after her account is created - seems like this could live happily in the create
action that we don’t have.
So we seem to have at least 2 options.
- We can extend the Devise
registrations_controller
and add anafter_action
to thecreate
action that sends a welcome email. I probably should have done this. - We can add an
after_create
callback in theUser
model that sends the email. Needless to say, this is what I did.
Now this toxic seed was planted weeks before it grew into a full banning from SendGrid, thanks in part to another handy Rails gem called Letter Opener.
Instead of sending an actual email to fbipplebap@gmail.com, Letter Opener just shows us a pretend HTML email in our browser.
The Main Event
So we’re using Letter Opener in our development environment, but not for our staging environment, because in staging, we want to see that emails actually get delivered.
Now you can probably see where this is headed. Here are the magical 10 seconds that led to my banning:
On my Heroku dashboard for the staging site, I added the SendGrid add-on. (3 seconds)
Then, I seeded the staging database: rails db:seed
. (3 seconds)
Then, 100 Harry Potter dummies were created. The after_create
callback mentioned above is fired 100 times, and 100 emails are sent to Harry Potters. And 100 emails bounce. (4 seconds)
I set up my computer to fail. And SendGrid’s computer is smart enough to notice my 100% bounce rate, and promptly banned me.
A Better Approach
Instead of the after_create
callback on the model, I could have extended the Devise controller, and used an after_action
.
The difference between these two approaches may seem minor, but the difference between being banned and not being banned is major.
The after_create
method will fire any time a record is created for the corresponding model - i.e. User.create
This could happen from the console, the seed file, or from inside a controller somewhere. My self-inflicted damage happened in the seed file.
If I had used an after_action
in a controller, I would have been safe. This is because the controller action is only called from a specific route - when the user actually interacts with the UI. The controller action is unrelated to me calling User.create
somewhere else in my code.
Another Approach
Use real emails! This was actually my first fix. I created an alias email in the Google Apps admin (t@bounce.so) that gets forwarded and skips the inbox. And in the seed file, just used something that looked like this:
100.times do |i|
u = User.new
u.email = "t+#{i}@bounce.so"
u.save
end
Post Morten
SendGrid, please unban me!