You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Django中为用户实现邮件退订功能?

在Django中实现邮件退订功能

我来帮你一步步搞定这个邮件退订功能,结合你现有的代码,咱们分这几个步骤来做:

1. 更新用户模型,添加订阅状态字段

首先得在你的User模型里加一个字段,用来标记用户是否愿意接收邮件。修改models.py:

from django.db import models
from django.contrib.auth.models import AbstractUser, UnicodeUsernameValidator
from django.utils.translation import gettext_lazy as _

class User(AbstractUser):
    username_validator = UnicodeUsernameValidator()
    username = models.CharField(
        _('username'),
        max_length=150,
        unique=True,
        help_text=_('Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.'),
        validators=[username_validator],
        error_messages={
            'unique': _("A user with that username already exists."),
        },
    )
    first_name = models.CharField(_('first name'), max_length=30, blank=True)
    last_name = models.CharField(_('last name'), max_length=150, blank=True)
    email = models.EmailField(_('email address'), unique=True)
    # 新增订阅状态字段,默认开启订阅
    email_subscribed = models.BooleanField(_('email subscribed'), default=True)

然后执行迁移命令更新数据库:

python manage.py makemigrations
python manage.py migrate

2. 修改邮件发送视图,只给订阅用户发邮件

接下来修改你views.py里的email_users_date函数,只给email_subscribed=True的用户发送邮件,同时修正原代码里msg未定义的问题:

@csrf_exempt
def email_users_date(request):
    if not request.method == 'POST':
        return HttpResponse(status=400)
    json_data = json.loads(json.loads(request.body)[0])
    date = json_data.get('date')
    # 只筛选订阅了邮件的用户
    subscribed_users = User.objects.filter(email_subscribed=True)
    for user in subscribed_users:
        subject = 'Data updated'
        template = get_template('interface/emaildata.html')
        context = {'user': user, 'date': date}
        # 渲染HTML邮件内容
        html_msg = template.render(context)
        text_msg = strip_tags(html_msg)
        send_mail(subject, text_msg, settings.DEFAULT_FROM_EMAIL, [user.email], html_message=html_msg)
    return HttpResponse(status=200)

3. 创建安全的退订视图和URL

我们用Django的signing模块生成带签名的URL,防止恶意篡改用户订阅状态。

3.1 编写退订视图

在views.py里添加:

from django.core import signing
from django.shortcuts import render
from django.contrib import messages

def unsubscribe(request, signed_user_id):
    try:
        # 验证签名,链接30天内有效
        user_id = signing.loads(signed_user_id, max_age=30*86400)
        user = User.objects.get(id=user_id)
        user.email_subscribed = False
        user.save()
        messages.success(request, '你已成功退订邮件,感谢你的支持!')
    except (signing.BadSignature, User.DoesNotExist):
        messages.error(request, '退订链接无效或已过期,请尝试重新获取')
    return render(request, 'interface/unsubscribe_confirm.html')

3.2 配置URL

在你的应用urls.py里添加:

from django.urls import path
from . import views

urlpatterns = [
    # 其他URL...
    path('unsubscribe/<str:signed_user_id>/', views.unsubscribe, name='unsubscribe'),
]

4. 在邮件模板中添加退订链接

最后,在邮件模板里添加安全的退订链接。首先修改邮件发送视图的context,生成签名后的用户ID:

# 在email_users_date函数的context中新增签名ID
from django.core import signing

context = {
    'user': user,
    'date': date,
    'signed_user_id': signing.dumps(user.id)
}

然后在interface/emaildata.html邮件模板的底部添加:

<p>不想再收到此类邮件?<a href="{{ request.scheme }}://{{ request.get_host }}{% url 'unsubscribe' signed_user_id %}">点击这里退订</a></p>

这个链接会生成一个安全的、带签名的退订地址,用户点击后就能直接取消订阅。

可选:添加重新订阅入口

如果需要支持用户重新订阅,可以在个人中心页面添加一个开关,或者创建类似的重新订阅视图,逻辑和退订一致,只是将email_subscribed设为True即可。

内容的提问来源于stack exchange,提问作者user8427236

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 03:23:37