Secure way to undo an Opt-Out - email

Our WebApp allows members to send emails to other members and non-members for collaboration. Because I don't want to spam anyone, each mail to a non-member contains a link to opt-out from further mails. (Members can manage their mail preferences from within the app).
I wanted to respect the opt-out request without storing personally identifiable information such as the email address in our system, which is why I went for a hash-based implementation. Before a email is sent, the recipient is checked agains the opt-out list.
My opt-out table consist of the hash of the email address and an undo token:
hash(lowercase($email)), hash($undo_token)
The undo token is sent to the user along with the confirmation of the opt-out, should they change their mind. This token is required to remove an entry from the opt-out table.
However, people seem to delete those mails and we have received several requests that they want back in.
What is a secure, hard to abuse and automated way to undo an opt-out?
The solution should not allow a person to opt-in someone else. I also don't feel like sending emails to an address that is in my opt-out list without being sure it's them.
I am looking especially for links/references to credible and/or official sources. Thank you.

I'm sorry, I don't have any credible sources for you but this is just my thought. I have seen some unsubscription links look like http://some-email-service.com?action=OptOut&secretToken=3648789036219699210blahblahblah. They use something like action=OptOut passed as a GET parameter. If you too are using some similar approach to unsubscribe the user, why don't you just use action=UndoOptOut to reverse the action? Moreover, if the OptOut confirmation email that you send is deleted by the user, then there is no other way to undo it other than the user explicitly subscribing again.

Related

SendGrid - How to hide the "View Opt Out Preferences" button from Opt-Out Preferences page

We only enable unsubscribe links for all the marketing emails.(we have unsubscribe groups for that) So we don't provide unsubscribe links for other types of email, for example, a payment request email.
However, we discovered that on the Preferences page, users can still choose to Opt-Out of all Emails (global unsubscribe) thus they will no longer receive any email from us including the payment request. So wondering how could I disable this "View Opt Out Preferences" button so that users can only Opt-out one single group?
Edit Sep 20:
there is no such setting for custom unsubscribe link. Offical docu is out of date.
https://docs.sendgrid.com/ui/sending-email/create-and-manage-unsubscribe-groups#using-a-custom-unsubscribe-link
Twilio SendGrid developer evangelist here.
Sorry it's taken me a while to get to this. I've been chasing down what can be done here. There are a few options:
Subusers
If you are on a Pro account or higher, you can set up subusers within your account. The recommendation is to set up a subuser for your marketing emails and a different subuser for your transactional emails. That way unsubscribes from the marketing list won't affect the transactional email side of things. You can read about setting up subuser accounts here.
Create your own unsubscribe page
Rather than using the SendGrid provided unsubscribe page, that allows users to get to the "Opt out of all emails" button, you can create your own unsubscribe page. You can add a custom unsubscribe link to your emails. You can then use the API to add the email address to one of your unsubscribe groups.
Bypass suppressions
You can set the bypass_list_management filter to true when sending your mail to ignore all unsubscribe groups/suppressions. This seems like a last resort sort of fix, rather than something you should use for all transactional emails. The docs are fairly strongly worded on this:
It is important to respect unsubscribes, and these filters should be used only when it is absolutely necessary to deliver a message to recipients who have unsubscribed from your emails. For example, you may use these filters to deliver messages that you are legally required to send to all recipients or important security messages like a password reset.
Check out more on bypass list management.

Managing user opt-in with Mailgun

I have an app which sends a daily reminder message. If a user forgets to log in on certain days, it will send an email reminder. I want users to be able to unsubscribe to this reminder by clicking a link on the email. There may also be different kinds of subscription. For example, a user might not want daily emails, but they may want password reset, or blog emails.
Mailgun has an unsubscribe feature. While this allows some control with tags, this seems to lack a resubscription option. They also have a mailing list, but that also seems more for blasting emails rather than opting in to notifications.
One option is to connect the email to my database. So that when the user clicks an unsubscribe link, it will flip a flag in my database such that the user isn't contacted regarding this email. But I can't find a way to do this, that doesn't involve giving the user an API link on the emails.
What are some options I can do to solve this?
You probably would be able to accomplish this using Mailgun mailing lists (but I wouldn't for reasons below). You'd have to maintain a list for each type of email that you want to send to users. So when you add/delete users from your system you'll have to use the API or control panel to add/remove from each of the lists. Mailgun can generate a unique unsubscribe url for each of the lists so that when the user hits unsubscribe from the email it will flag the email as unsubscribed for that one list.
From Mailgun docs:
For managing unsubscribes in Mailing Lists, you can use
%mailing_list_unsubscribe_url%. We will generate the unique link to
unsubscribe from the mailing list. Once a recipient clicks on the
unsubscribe link, we mark the recipient as “unsubscribed” from this
list and they won’t get any further emails addressed to this list.
Mailing lists should work unless I don't understand your requirement.
From my point of view I'd just prefer to handle this inside my own system. Otherwise you have to maintain your application's user records and then a separate mailgun list for each email type. In multiple applications I have user email preferences stored in the db. The user (or customer admin login) can adjust preferences through the UI or in some cases by hitting unsubscribe link in an email which links to a web page (part of my app) "You have now unsubscribed to daily emails" -- the page sets the user as unsubscribed in my app DB.
Its extra work but the advantages to handling this in your app is:
You've only got one user DB (list) to maintain
List membership is easier to modify by the app user or app user account manager
It doesn't tie you as tightly to Mailgun -- in case you decide to
choose another provider
More on Mailgun Mailing lists:
https://documentation.mailgun.com/en/latest/user_manual.html#mailing-lists

How much of a bad idea is it to allow users to send arbitrary emails via our servers

My company is developing a cloud contact management service and on our iOS app we're having some problems launching a particular enterprise email client app when the user presses the "Email" button on one of their contacts.
One member of our team came up with an idea to get around the problems with this enterprise app:
We let the user specify their email address in the app's settings and create our own email composing screen. Tapping the email button on a contact would open the composing screen, they would write their message and then we would send it on their behalf from our servers (or via service like mailchimp).
Basically, this would mean we would have to create an endpoint on our api that would accept a POST request with 'from', 'to', 'subject', and 'body' fields which would send the appropriate email.
This seems like a very bad idea as it's essentially creating a free, anonymous email service that could easily be abused send spam.
A few extra notes about our setup:
We don't verify an accounts email when they sign up
Even if we did verify the account's email, the user would need to be able to specify any email, as they may have signed up with personal email, but want to email someone from their work email.
Our API doesn't currently have any kind of rate limiting
Instead of having a from field in the request, we could instead send the id of the contact they want to email. This doesn't really change anything because if someone wants to abuse the send email endpoint they can also abuse the create contact endpoint.
So exactly how much of a bad idea is this, and how can I convince my team not to do this?
A few thoughts against doing it:
This is the perfect spamming service, which could damage the reputation of your company (reputational risk).
Your email servers would very quickly make it into blacklists (RBLs), making your outgoing emails land in spam folders in very many recipients' mailboxes.
Even if your servers are not yet in RBLs, if you send a forged email like that and proper email security is set up at the recipient end, your emails will still have a good chance to get classified as spam. Have a look at things like SPF and DKIM.
This could even have legal implications. Imagine the scenario when one of your users uses this service for something like blackmail. Would you be able to prove it was not you? Probably yes with the right controls, but would you want the hassle?
Still on the legal side, many countries (the EU, mainly) have data protection regulations which strictly control how personal data like email addresses can be used, especially for commercial advertisement. You probably want to adhere to that, but that would be hard with such a service (note that I'm not a lawyer, in such a case it's probably the abuser of your service that would offend these regulations and not you, I don't know, but it's something to consider).
If anyone can just send emails, it will be fairly easy to perform a denial of service attack against your services.
A few controls you could implement to mitigate some risks:
When adding a sender (from) address, you should validate that by for example sending a (cryptographically random) token and checking if the user can send it back (eg. by clicking a link in the email). If he can, that proves to some extent that he controls the email address and is probably a valid sender.
Limit the possible recipient addresses if you can. The best would be if recipients had to opt in to receive emails. If this is not possible, at least let recipients opt out from further emails. For this, you would have to add something like a footer to emails with "never again" links, and implement a facility to maintain recipients to which you must not send anymore.
Implement rate limiting. Depending on your exact scenario and use case, only allow to send the least number of emails acceptable for your application.
Implement proper logging so that you have an audit log of who exactly sent what email to whom. For this, log metadata like IP addresses as well. For this, you will likely have to authenticate your users.
On an operational level, have monitoring in place, and be prepared to ban offending users, based on a clear ToS shared with your users.

Mailchimp? Mandrill? or both?

I am a bit confused with Mailchimp and Mandrill, what I need to do seems to need both, let me explain:
A social network needs to send at 1am everyday a notification email to their users that have not logged in during the last 24 hours. Emails have to be personalised.
On the top of that, there are different campaigns for different list of users.
My first thought is to use the mandrill API, but I need to be able to see who unsubscribe from what campaign (a user might want to unsubscribe to one campaign but stay subscribed on another one). I cannot seem to find something that fits the bill with Mandrill... Subaccount? Tags?
Thanks!
I'm not 100% sure this will answer the question, but let me try:
Mandrill actually belongs to MailChimp, and was created for interfacing with it. You can use the "mandrill-api" gem - https://mandrillapp.com/api/docs/ - to interface with many of the Mandrill and MailChimp features to do the things you wanted.
A lot of times if you are attempting to do so, and run into errors such as "XXXX not found", you have to send it FROM MailChimp TO Mandrill. For instance, when you create a template in MailChimp, click the dropdown menu next to the template, and click "Send to Mandrill". You should be good from there.
Other than that, I wish you luck. While the mandrill-api gem can do everything, it has absolutely abysmal documentation. There are multiple third-party gems that provide similar functions (mandrill-rails is a popular one) that you might have better luck with, but I have not used them myself.
Notifications = Mandrill = 1:1 emails
Campaigns = MailChimp = 1:many emails
Typically, notifications are 1:1 emails - your system sends a single user an email as a result of some trigger within the system. The trigger might match multiple users at the same time, but emails are sent to them each individually - probably via a loop in your code. Mandrill supports templates to personalise these emails if required.
Campaigns are sent to mailing list members in bulk, where the same (personalised) email is sent to multiple users at the same time. This is either triggered by hand (you manually create and send a campaign) or is based on a scheduled trigger (eg autoresponders or scheduled campaign mailing).
Notifications are generally system-related emails and while you do have the technical ability to let users unsubscribe from them in Mandrill, typically I would consider that a configuration option you'd give them in their personal control panel on your site.
Campaigns are something you MUST allow users to unsubscribe from to comply with anti-spam laws, so will contain unsubscribe links in the footer of every email.

How should email address opt-in implemented?

Scenario:
User gives you an email address. Before they can sign up for services, they need to validate the email address - you email out a URL, they click on it, then they can subscribe to the services.
Questions:
What does the URL look like? I'm thinking a random guid would be OK.
Do you use that same random key for unsubscribe requests?
Are there any good open source implementations of double-opt in I should be looking at?
I've used a random GUID before such purposes to verify email accounts, and it works well. Unless you are dealing with ultra-secure, ultra-sensitive data then it should suffice. I see no reason not to use the same GUID for unsubscribe requests - that way you just need to store one GUID per account that can be a lookup to your subscribers database (or however you store them). You could add the unsubscribe link to the bottom of all emails, making it a simple one-click option.
This is pretty simple to implement with a random string and a GET request. I probably wouldn't use the same for unsubscribe, because you know most people are going to lose the original email. Do it the same way -- they say they want to unsubscribe, and it does so, but also sends an email saying you've been unsubscribed in case it was an accident.
Edit: You wouldn't even need to ensure a unique string, since you'd pass in the email address too.