14

I have a simple rails app where user can send a mass email to 10+ people. In this email I'd like to always have a link at the bottom which the end user can click to unsubscribe himself from the notifications. I don't have much idea how I should tackle this.

can there be just a generic link in the email which users click then enter their email address to unsubscribe themselves? But problem with this is that some other user could unsubscribe someone else.

I would like to generate a specific unique link for each email so that when user clicks it, it automatically removes that user from the list rather than user having to do some extra work.

Where should I start in order to implement this?

Patrick
  • 475
  • 2
  • 6
  • 16
  • Hi @Patrick, can you share your final solution with me as I am looking to the same, Thanks – iCyborg Jul 26 '13 at 15:42
  • 2
    you can try this tutorial, very helpful http://ngauthier.com/2013/01/rails-unsubscribe-with-active-support-message-verifier.html – duykhoa Aug 28 '13 at 09:43

2 Answers2

17

Your unsubscribe links could look like this: http://host/application/unsubscribe?address=example@example.com&token=598bbdf39bc8f27b07fe85b6a7dd8decef641605

Generate the token using the email address and a magic token. Ideally, you'd use HMAC with SHA256, but even just sha1 should be 'good enough':

$ echo "secret token example@example.com" | sha1sum
598bbdf39bc8f27b07fe85b6a7dd8decef641605  -

The secret token portion would be fixed in your application, and the example@example.com needs to match the email address.

Of course, if the secret token ever gets revealed, you're back to anyone unsubscribing everyone. You could also store per-user magic tokens in your database to validate the tokens in URLs, that wouldn't be much more difficult than this, and definitely much safer.

sarnold
  • 102,305
  • 22
  • 181
  • 238
  • I like this idea. but few questions. How do I generate that token from inside rails? and that token will be associated with each person who gets the email right? (a new column in DB). So when user clicks to unsubscribe, my rails code reads the token....does lookup on table and unsubscribes if it finds a person with that token – Patrick Aug 02 '10 at 11:45
  • @Patrick, [Jesse's](http://stackoverflow.com/users/363881/jesse-wolgamott) answer includes `SecureRandom`, which sounds like a great source for magic tokens. You could either store the token in your User model or create a new table with just user id and unsubscribe tokens, and populate it as you send emails. – sarnold Aug 02 '10 at 23:36
  • 2
    How would this compare to using just a token that contains the encrypted email address (not hashed), and a secret token or two, then decrypting them to check in the application that the secret tokens agree with the email address? I'm thinking the secret tokens could be things that already exist such as an id of the user or the date added. – Michael K Jan 07 '13 at 20:38
3

If you have a model for EmailTemplate and a model for Subscriber, then your code might look something like:

@email_template = EmailTemplate.find(3)
@email_template.subscribers.each do |subscriber|
  Notifier.deliver_template(:email_template=>@email_template, :subscriber=>subscriber)
end

so, you could change to

email_delivery = EmailDelivery.create(:email_template=>@email_template, :subscriber=>subscriber)
Notifier.deliver_template(email_delivery)

And then the email_delivery's before_create generates a token. A random password generator per email_delivery should be good. SecureRandom does a good job at random tokens: p SecureRandom.hex(10) #=> "52750b30ffbc7de3b362"

Include that email_delivery token in your email, and then do a lookup based solely on that.

Jesse Wolgamott
  • 40,197
  • 4
  • 83
  • 109