What is the best way to handle Email exceptions in a Rails app using Postmarkapp?
Asked Answered
S

1

8

I am using Postmark to handle all email in my Rails 3 app, using postmark-rails gem.

Now and then an user introduces a wrong email or a non-existing one with ends up giving hardbounces. Postmark raises Postmark::InvalidMessageError errors to handle this issue, that my users receive as a non-descriptive 500 error.

I'd like to handle those errors into my responsive interface and I was wondering what would be the best strategy. I have now a few mailers already with several dozens amongst all, so I don't want to add begin-raise blocks to all those methods. Adding this begin-raise to controllers also doesn't seem the most elegant solution.

I've been reading about adding a rescue_from block to my ApplicationController, but then I don't know how to handle this in the interface (maybe by calling a method that uses errors method?)

I'd like to listen to your thoughts before plumbering.

Any ideas?

Sewellyn answered 4/10, 2011 at 2:15 Comment(0)
L
26

We had to deal with the same problem in Beanstalk. First of all we turned off "raise_delivery_errors" in production then we implemented an override method for ActionMailer::Base that allowed us to change that setting on the fly for specific deliveries. Like this:

AccountMailer.raise_errors do
  AccountMailer.deliver_welcome_email(@account)
end

That allowed us to control when exactly we want delivery exceptions appearing and avoid problems when such errors were breaking something they shouldn't. Usually there are only one or two places where you'd want to put that override. In our case it's Forget Password and Invite User functions, when it's crucial to let users know that their password reset email/invitation wasn't delivered. Having a delivery exceptions somewhere inside a background-running job doesn't help anyone.

After we had that in place we added a rescue_from to our ApplicationController that would set flash[:alert] and redirect back.

def postmark_delivery_error(exception)
  if address = derive_email_from_postmark_exception(exception)
    link = %Q[<a href="#{ reactivate_email_bounce_path(address)  }">reactivating</a>]
    msg = "We could not deliver a recent message to “#{ address }”. The email was disabled due to a hard bounce or a spam complaint. You can try #{ link } it and try again."
  else
    msg = "We could not deliver a recent message. The email was disabled due to a hard bounce or a spam complaint. Please contact support."
  end
  flash[:alert] = msg
  redirect_to :back
end

reactivate_email_bounce_path links to a controller that uses Postmark API to reactivate bounces. You can find more details about it here:

http://developer.postmarkapp.com/developer-bounces.html

So after you have all that in place your end user can have a pretty nice experience dealing with delivery errors, something that's not usually addressed in web apps. It looks like this in Beanstalk:

Beanstalk reactive bounce

And not only a user can see that his email bounced, he can also reactive it himself:

Beanstalk reactivate bounce

Hope this helps.

Ilya Sabanin http://twitter.com/isabanin

Lacy answered 8/10, 2011 at 4:46 Comment(4)
Dear Ilya, WOW, many thanks for the great answer !!! sorry about the delay in getting back, I had to leave this issue aside for a while. Are you planning to open source this code into a gem? I'd definitely use that and try to contribute. In the meanwhile, can you provide more information on the reactivate_email_bounce_path action in your controller? I will try to implement my own solution and keep this question open till I can get it working, after that I'll mark your answer.Sewellyn
Thanks. It will be hard for me to show how our controllers look like inside because there's a lot of logic in there that's not related to the problem. However the solution to reactivate bounces is pretty simply. You just need to send an HTTP request to Postmark API. You can find more details here: developer.postmarkapp.com/…Lacy
Insane answer. Very well handled. I'll be implementing this verbatim into our application. Thank you!Noodle
This is a fantastic answer, but any idea how to handle exceptions if you are using DelayedJob?Stodgy

© 2022 - 2024 — McMap. All rights reserved.