如何在Flask发送的订阅通知邮件中添加退订超链接?
Flask订阅邮件添加退订超链接解决方案
1. 将纯文本邮件改为HTML格式
原邮件为纯文本格式,无法解析超链接,需切换为HTML邮件并设置正确的Content-Type头。修改邮件发送代码如下:
from email.mime.text import MIMEText # 构造HTML格式的邮件内容,替换为你的域名和订阅者ID subscriber_message = f""" <html> <body> <p>You have been subscribed. Thank you.</p> <p>If you wish to be removed from the subscription list, <a href="https://your-domain.com/auth/unsubscribe/{subscriber.id}">click here</a>.</p> </body> </html> """ # 封装HTML邮件,设置必要头信息 message = MIMEText(subscriber_message, 'html') message['From'] = my_email message['To'] = subscriber_email message['Subject'] = "Subscription Confirmation" server = smtplib.SMTP("smtp.gmail.com", 587) server.starttls() server.login(my_email, pw) server.sendmail(my_email, subscriber_email, message.as_string()) server.quit()
说明:需将your-domain.com替换为你的实际域名,subscriber.id是当前订阅者在数据库中的唯一ID,用于生成专属退订链接。
2. 调整退订路由,支持用户点击操作
原delete-subscribers接口仅支持POST请求,无法直接通过链接触发(链接默认是GET请求),推荐以下两种实现方式:
方式一:新增退订确认页面(更友好)
先让用户确认退订操作,再执行删除逻辑:
# 显示退订确认页面 @auth.route('/unsubscribe/<int:subscriber_id>', methods=['GET']) def unsubscribe_confirm(subscriber_id): sub = Subscribers.query.get(subscriber_id) if not sub: flash('Subscriber does not exist in database.', category='error') return redirect(url_for('home')) return render_template('unsubscribe_confirm.html', subscriber=sub) # 处理退订请求(兼容原POST逻辑) @auth.route('/delete-subscribers', methods=['POST']) def delete_subscribers(): # 优先从表单获取ID,兼容原JSON传参逻辑 subscriber_id = request.form.get('subscriber_id') if not subscriber_id: sub_data = json.loads(request.data) subscriber_id = sub_data['subscribersId'] sub = Subscribers.query.get(subscriber_id) if sub: db.session.delete(sub) db.session.commit() flash('Successfully unsubscribed.', category='success') else: flash('Subscriber does not exist in database.', category='error') return redirect(url_for('home'))
对应的unsubscribe_confirm.html模板示例:
<!DOCTYPE html> <html> <head> <title>Unsubscribe Confirmation</title> </head> <body> <h1>Are you sure you want to unsubscribe?</h1> <form method="POST" action="{{ url_for('auth.delete_subscribers') }}"> <input type="hidden" name="subscriber_id" value="{{ subscriber.id }}"> <button type="submit">Yes, Unsubscribe Me</button> <a href="{{ url_for('home') }}">Cancel</a> </form> </body> </html>
方式二:直接通过GET请求完成退订(简化版)
若无需确认步骤,可直接在GET路由中执行删除:
@auth.route('/unsubscribe/<int:subscriber_id>', methods=['GET']) def unsubscribe(subscriber_id): sub = Subscribers.query.get(subscriber_id) if sub: db.session.delete(sub) db.session.commit() return "Successfully unsubscribed." else: return "Subscriber does not exist in database."
这种方式操作简单,但存在误触风险,需根据业务场景选择。
3. 安全优化建议
直接使用订阅者ID易被恶意批量攻击,建议为每个订阅者生成唯一退订token:
- 修改
Subscribers模型:
from uuid import uuid4 class Subscribers(db.Model): id = db.Column(db.Integer, primary_key=True) email = db.Column(db.String(100), unique=True, nullable=False) # 添加唯一退订token字段 unsubscribe_token = db.Column(db.String(64), unique=True, nullable=False, default=lambda: str(uuid4()))
- 更新邮件链接:
f"<a href='https://your-domain.com/auth/unsubscribe/{subscriber.unsubscribe_token}'>click here</a>"
- 修改退订路由:
@auth.route('/unsubscribe/<token>', methods=['GET']) def unsubscribe(token): sub = Subscribers.query.filter_by(unsubscribe_token=token).first() if sub: db.session.delete(sub) db.session.commit() return "Successfully unsubscribed." else: return "Invalid unsubscribe link."
内容的提问来源于stack exchange,提问作者Dustin916
相关产品推荐
相关产品推荐

