Django密码重置邮件仅本地生效,部署后无法发送求助
问题解决:跨环境密码重置邮件发送失败
问题原因分析
核心问题是邮件中的重置链接触发了邮件服务商的反垃圾机制,或动态生成的链接不符合邮件服务器安全规则:
request.build_absolute_uri依赖请求的Host头,通过Nginx/VPS访问时,可能生成内网IP或未备案域名的链接,被判定为恶意内容拦截。- 你传递了空的纯文本邮件内容,部分严格的邮件服务器会拒收仅含HTML格式的邮件。
修复方案
1. 替换动态链接生成方式,使用固定公网地址
不依赖请求对象生成链接,直接从配置文件读取公网访问地址,避免生成不可访问的内网链接:
首先在settings.py添加配置:
# settings.py BASE_URL = "https://your-public-domain.com" # 替换为你的公网域名或VPS公网IP
修改视图中的链接生成代码:
def password_reset_request(request): if request.method == "POST": form = PasswordResetRequestForm(request.POST) if form.is_valid(): cpf = form.cleaned_data['cpf'] user = CustomUser.objects.get(cpf=cpf) token = default_token_generator.make_token(user) uid = urlsafe_base64_encode(force_bytes(user.pk)) # 手动构建重置链接,替代request.build_absolute_uri reset_path = reverse('password_reset_confirm', kwargs={'uidb64': uid, 'token': token}) reset_link = f"{settings.BASE_URL}{reset_path}" # 使用配置的公网地址 # 其余代码保持不变...
2. 补充纯文本版本的邮件内容
空纯文本内容会被部分邮件服务器判定为异常,添加纯文本版本:
try: # 编写纯文本邮件内容 plain_text_content = f"""Hello {user.username}, We received a request to reset your account password. Use the link below to set a new password: {reset_link} This link is valid for 24 hours. If you didn't request this, you can safely ignore this email. Best regards, CIGMA Team""" send_mail( theme, plain_text_content, # 替换原空字符串位置 settings.DEFAULT_FROM_EMAIL, [user.email], html_message=email_content, fail_silently=False, ) print("Email sent successfully!") except Exception as e: print(f"Email sending failed: {e}")
3. 配置Nginx正确传递请求头(若使用反向代理)
如果用Nginx部署,需确保传递正确的Host头和协议信息,避免生成错误链接:
server { # 其他配置... location / { proxy_pass http://127.0.0.1:8000; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-Proto $scheme; # 传递http/https协议 } }
同时在settings.py添加:
USE_X_FORWARDED_HOST = True SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') # 启用HTTPS时添加
验证步骤
- 用公网IP/域名访问系统,发起密码重置请求
- 查看控制台输出的
reset_link是否为正确的公网地址 - 检查收件箱(含垃圾邮件文件夹)是否收到邮件
内容的提问来源于stack exchange,提问作者vinicius cigma
相关产品推荐
相关产品推荐

