0

I am working on implementing 'Unsubscribe link' on my emails. I am maintaining a table for unsubscribed users.

I want to know the email address once the user clicks on the unsubscribe link. Of course, I cannot send it as a get parameter as one could easily modify it.

A eg. situation is - I want to send emails to 10 of my friends and each email is an HTML email and has a unsubscribe URL, so if the user clicks on the link then he gets added to my UnsubscribedUser model, and then I don't send emails to them.

I want to somehow encrypt the email address, pass it as a get parameter and then decrypt it in the view and store it in my database. I don't know how should I go about doing this in Django. If there is some better way to implement this please let me know.

Shahrukh Mohammad
  • 985
  • 2
  • 17
  • 33

2 Answers2

1

Typically encryption is not a good idea either, since if the decryption key gets known, people can decrypt all possible content, furthermore it would also make it rather easy to start hacking this application with the encryption key: if I somehow find out the encryption key, I can construct a URL to for example reset the password of an arbitrary email address, and thus reset the password of Bob, and login as Bob later.

A typical solution for this is constructing a table of "unsubscribe sessions". In case somebody requests to unsubscribe, you add that person to the table, and you add some sort of random id to it. It is better not to use things like a primary key, since it is predictable what the previous and next ids will be, and then people can "hack" this system to confirm the unsubscription of another person.

We thus create a table, with for example a GUID (globally unique identifier):

from datetime import datetime, timedelta
from django.conf import settings
from django.db.models import CASCADE, DateTimeField, ForeignKey, Model, UUIDField
from uuid import uuid4

def tomorrow():
    return datetime.now() + timedelta(days=1)

class UnsubscribingUser(Model):
    uuid = UUIDField(default=uuid4, editable=False, unique=True)
    user = ForeignKey(settings.AUTH_USER_MODEL, on_delete=CASCADE)
    expires = DateTimeField(default=tomorrow)

So now in case you want to unsubscribe somebody, you can construct such UnsubscribingUser model instance, and send an email with a link:

def unsubscribe(request):
    uu = UnsubscribingUser.objects.create(user=request.user)

    # send mail with uu.uuid
    # ...
    pass

The email then should contain a URL that links to a view that process the UUID:

from datetime import datetime
from django.http import Http404

def unsubscribe_url(request, uuid):
    uu = get_object_or_404(UnsubScribingUser, uuid=uuid)
    if uu.expires <= datetime.now():
        # unsubscribe logic
        # ...
        uu.delete()
    else:
        # too late
        # do something in that case, for example
        uu.delete()
        raise Http404

We thus first check if there exists such UnsubscribingUser model instance, in that case we check if the "session" already expired. If not we unsubscribe.

The email thus contains the reverse(unsubscribe_url, uuid=uu.uid) URL. Expiring is typically desirable, since otherwise eventually the table will store a huge amount of UUIDs, and after a white it becomes more likely that entering a random UUID can unsubscribe a random person.

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
  • thanks a lot, this solution is good, but I am not sure how it will work in my case. I am editing my question to better explain my needs - Suppose I have a few emails of my friends and I am sending them HTML emails each having a unsubscribe URL, so each of the email's unsubscribe URL will be different from what other friends get, and the URL will have the email(somehow) which I will then store in db, in the case of your solution, I have to create a `UnsubscribingUser ` instance for each of the user, which might not be good if I send email to large no.of users and only a few unsubscribe – Shahrukh Mohammad Jul 01 '18 at 15:56
  • my use case is simple, I just need to somehow encrypt my email in my URL for unsubscribe. – Shahrukh Mohammad Jul 02 '18 at 04:46
0

for encrp.

import crypt
# To encrypt the password. This creates a password hash with a random salt.
password_hash = crypt.crypt(password)

# To check the password.
valid_password = crypt.crypt(cleartext, password_hash) == password_hash
Flair
  • 2,609
  • 1
  • 29
  • 41