前言
在上一篇博客《【Web应用开发笔记】Django笔记10:用户账户功能开发》我介绍了用户账户相关的基本功能,包括:
- 注册
- 登录
- 登出
- 修改用户信息
- 修改密码
- 忘记密码时通过邮件重置
- 修改密码
不过上一篇还有一些遗留问题,比较典型的就是:没有真正发送邮件,而是仅向后端发送了验证信息。
本文将解决这个问题,在重置密码时真正的发送邮件。
1. 谷歌邮箱应用授权
-
step1:谷歌账户,启用两步验证
- 这里我仅设置了手机验证。
https://myaccount.google.com/security

- 这里我仅设置了手机验证。
-
step2:创建应用并获取密码
- 密码出现后需要复制并手动保存
https://myaccount.google.com/apppasswords

- 密码出现后需要复制并手动保存
2. Django 代码
2.1 settings.py
- 在 settings.py 中新增了如下内容
- 需配合 .env 文件
python
# email
EMAIL_BACKEND_MODE = env.str("EMAIL_BACKEND_MODE")
if EMAIL_BACKEND_MODE == "gmail":
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
EMAIL_HOST = "smtp.gmail.com"
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = env.str("EMAIL_HOST_USER")
EMAIL_HOST_PASSWORD = env.str("EMAIL_HOST_PASSWORD")
DEFAULT_FROM_EMAIL = f"YourSite <{EMAIL_HOST_USER}>"
else:
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
- 注
- 这样已经可以了
- 因为我们使用的是 Django 内置的 用户重置密码 的功能,因此无需开发 views
- 其他代码详见《【Web应用开发笔记】Django笔记10:用户账户功能开发》
- 只需要配置一种类型的邮箱
- 这是作为发件邮箱
- 和用户收件邮箱没关系,用户重置密码时可以填自己的任意类型的邮箱
- .env 文件详见下节
- 这样已经可以了
2.2 配置 .env 文件
- .env
- EMAIL_HOST_USER 填写你的 gmail 邮箱的 URL
- EMAIL_HOST_PASSWORD 填写刚刚保存的密码
bash
DATABASE_URL=postgres://zkding:dzk01015717@localhost:5432/learn_django
DEBUG=False
SECRET_KEY=G78qS44KcvwdXwVgvuihTHxUHItbsCKdckWwVllDviQ
ALLOWED_HOSTS=zkding.pythonanywhere.com
CSRF_TRUSTED_ORIGINS=http://zkding.pythonanywhere.com
PROXY_MODE=Clash
EMAIL_BACKEND_MODE=gmail
EMAIL_HOST_USER=google_user_name@gmail.com
EMAIL_HOST_PASSWORD=xxxx xxxx xxxx xxxx
- 配置说明
| 字段 | 用途 | 填写举例 |
|---|---|---|
| DATABASE_URL | 数据库 url | 可填: sqlite3 数据库URL ... |
| DEBUG | 是否开启 DEBUG 日志(后端打印报错信息) | True False |
| SECRET_KEY | 生产方法: python -c "import secrets; print(secrets.token_urlsafe())" | |
| ALLOWED_HOSTS | 部署时的网址(无需 http:// 开头),注释掉则采用 localhost | 可选择: 注释掉这个变量 填生产环境URL |
| CSRF_TRUSTED_ORIGINS | 部署时的网址(需要 http:// 开头),注释掉则采用 http://localhost | 可选择: 注释掉这个变量 填生产环境URL |
| PROXY_MODE | 网络代理模式 | 可填: 空字符串 Clash |
| EMAIL_BACKEND_MODE | 发送 email 的模式 | 可填: 空字符串 gmail |
| EMAIL_HOST_USER | EMAIL_BACKEND_MODE 非空时,写对应邮箱的网址 | 可填: 空字符串 邮箱URL |
| EMAIL_HOST_PASSWORD | EMAIL_BACKEND_MODE 非空时,写对应邮箱的应用授权码(不是邮箱密码) | 可填: 空字符串 邮箱应用授权码 |
- 配置举例
-
开发环境(不发邮件)
bashDATABASE_URL=postgres://zkding:dzk01015717@localhost:5432/learn_django DEBUG=True SECRET_KEY=G78qS44KcvwdXwVgvuihTHxUHItbsCKdckWwVllDviQ PROXY_MODE=Clash EMAIL_BACKEND_MODE= EMAIL_HOST_USER= EMAIL_HOST_PASSWORD= -
开发环境(发邮件)
- <=== [TODO] 标记指向需要根据实际情况改的部分
bashDATABASE_URL=postgres://zkding:dzk01015717@localhost:5432/learn_django DEBUG=True SECRET_KEY=G78qS44KcvwdXwVgvuihTHxUHItbsCKdckWwVllDviQ PROXY_MODE= EMAIL_BACKEND_MODE=gmail EMAIL_HOST_USER=XXX@gmail.com <=== [TODO] EMAIL_HOST_PASSWORD=xxxx xxxx xxxx xxxx <=== [TODO] -
生产环境
- <=== [TODO] 标记指向需要根据实际情况改的部分
bashDATABASE_URL=postgres://zkding:dzk01015717@localhost:5432/learn_django <=== [TODO] DEBUG=False SECRET_KEY=G78qS44KcvwdXwVgvuihTHxUHItbsCKdckWwVllDviQ <=== [TODO] ALLOWED_HOSTS=zkding.pythonanywhere.com <=== [TODO] CSRF_TRUSTED_ORIGINS=http://zkding.pythonanywhere.com <=== [TODO] PROXY_MODE= EMAIL_BACKEND_MODE=gmail EMAIL_HOST_USER=XXX@gmail.com <=== [TODO] EMAIL_HOST_PASSWORD=xxxx xxxx xxxx xxxx <=== [TODO]
-
3. 验证
本地启动服务,并测试重置密码功能。可以看到 我的 gmail 向我的 qq 邮箱发送了如下信息:

点击链接后进即可重新设置密码。
4. 附录1:关于Django 适配网络代理
-
我的 ubuntu 系统使用了 clash verge 做为网络代理工具
- 这对我的 addr 和 port 有影响
- 我需要在 Django 中适配这个网络代理
-
在 .env 中的配置
bash
PROXY_MODE=Clash
- 在 settings.py 中的配置
python
import socks
import socket
...
PROXY_MODE = env.str("PROXY_MODE")
if PROXY_MODE == "Clash":
# 让 Python 所有 socket 连接走 SOCKS5 代理
socks.set_default_proxy(socks.SOCKS5, "127.0.0.1", 7890)
socket.socket = socks.socksocket
-
依赖
-
ubuntu 终端安装基础工具
- 由于我使用了 clash 网络代理,因此 telnet 是无法通的
- 在上面的 settings.py 中专门做了适配,所以不用担心
bash# 1. 安装基础工具(通常已预装) sudo apt update sudo apt install libsasl2-modules mailutils # 2. 测试 SMTP 连接(验证网络通畅) telnet smtp.gmail.com 587 # 如果提示 command not found,安装 telnet: sudo apt install telnet # 3. 退出 telnet(如果连接成功) # 按 Ctrl+],然后输入 quit -
python 包
bashpip install PySocks
-
-
别忘了把新的包信息保存到 requirements.txt
bash
pip freeze > requirements.txt