Skip to content

Instantly share code, notes, and snippets.

@bensheldon
Last active June 12, 2020 21:06
Show Gist options
  • Save bensheldon/974c888c350eca7cfeff62b8bde6a1e6 to your computer and use it in GitHub Desktop.
Save bensheldon/974c888c350eca7cfeff62b8bde6a1e6 to your computer and use it in GitHub Desktop.

Emails and SMS. Cousins or Sisters?

Many apps send both emails and SMS messages via Twilio.

My experience with GCF

Emails go out through Rails built-in Action Mailer construct

Raise your hand. Who here has worked with Rails Action Mailer?

ActionMailer:

  • Each email message is a self-contained class with error handling and lifecycle hooks (before action, after action).
  • Templates and localization largely built in
  • Backgroundable on the job queue (perform_now vs perform_later)
  • Testing harness built into Rails/Rspec and helpful tools like LetterOpener and Capybara-email for development and testing.
  • Conventional. 99% of Rails projects that send email probably use Action Mailer. Go look in the app/mailers directory: https://github.com/codeforamerica/gcf-backend/tree/master/app/mailers

SMS

  • SmsService.send_message(to:, body:) Do all the formatting/localization inline. Just a helper method that can be called in code anywhere.

In GCF, it’s common to send a similar message out by SMS and email, and it’s a mishmash of two different conventions/architectures that has been solved by in GCF by wrapping both of them in a job (yet another Rails Construct), and then not using most of the power of Mailers:

- inlining the message and not using Mailer templates
- using perform_now on the Mailer
- relying on the Job for error and retry handling and having to handle SMS and Email errors together

Example: https://github.com/codeforamerica/gcf-backend/blob/master/app/jobs/send_campaign_message_job.rb

Downsides:

  • In local development, it’s hard to simulate/inspect messages because they’re living on the job queue now which may not be run.
  • For testing one has to stub out SmsService differently than the Mailer’s testing harness.

What if sending an Emails or SMS worked the exact same way?

Rails has a way to customize the delivery method for Mailers where they don’t have to just go out via SMTP as Email.

Can create a custom ActionMailer Delivery Method: https://github.com/codeforamerica/drai/blob/master/config/initializers/twilio_sms_delivery.rb

Convention is that there is an “ApplicationMailer” and Mailer classes inherit from that.

In DRAI, there is an ApplicationEmailer and ApplicationTexter.

https://github.com/codeforamerica/drai/tree/master/app/mailers

  • Usage is the same regardless of whether it’s sent as an Email or SMS.
  • Allows treating them the same in tests.
  • Tools like LetterOpener (in development env it will pop open any newly sent email from the app in a new browser window) and Capybara-Email (system/integration tests that make it easy to open up emails and click links in them) work the same regardless of SMS or Email.
  • Error handling is much more laser-focused.

Badness.

  • There are some rough edges where Rails mostly assumes there will only be one primary delivery method within the application. In this case, Email and SMS are co-equals.
  • We frequently send very similar messages out by email or SMS. But the class-per-delivery-method means there is some similarly duplicated templates. Ended up with a hybrid of a SmsService simplicity but ActionMailer under the hood: https://github.com/codeforamerica/drai/blob/master/app/models/aid_application.rb#L575-L593
  • The configuration isn’t obvious. Another pair had a ticket to fix something and they were very confused.

But do I like it?

It’s ok. I’d like to figure out if I can use the same Mailer class, but just change delivery methods, so there would be two templates:

ApprovalMessageMailer.with(delivery_method: :sms).perform_later
ApprovalMessageMailer.with(delivery_method: :email).perform_later
  • views/mailers/approval_message/approval.html.erb
  • views/mailers/approval_message/approval.txt.erb
  • views/mailers/approval_message/approval.sms.erb
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment