如何使用Django和SMTP服务器发送邮件
关键要点
- 配置SMTP设置:通过在settings.py文件中配置适当的邮件后端、主机、端口和安全设置(如TLS)来设置Django邮件发送
- 使用Django Environ保护凭据:使用Django Environ通过环境变量安全管理敏感凭据,避免在源代码中硬编码凭据
- 生成应用特定密码:使用Gmail时,启用两步验证并创建应用密码来安全验证Django邮件发送
- 使用send_mail发送邮件:使用Django内置的send_mail函数从Django shell、视图或可重用辅助函数发送邮件
- 实现自动化联系表单:使用Django Forms构建自动化联系表单,并集成邮件发送功能
- 测试邮件功能:使用单元测试验证邮件发送逻辑,并使用MailHog或控制台邮件后端进行安全开发测试
- 遵循最佳实践:通过使用TLS加密、适当身份验证和模块化邮件功能确保安全高效的邮件传递
理解SMTP服务器和简单邮件传输协议
SMTP(简单邮件传输协议)是一组确定电子邮件如何从发件人传输到收件人的规则。SMTP服务器使用此协议发送和中继传出电子邮件。
SMTP服务器始终具有唯一地址和用于发送消息的特定端口,在大多数情况下为587。对于此示例,我们将使用Gmail的SMTP服务器:
创建Django项目
每个Django项目都应该有一个虚拟环境:
激活虚拟环境:
1
2
3
4
5
6
7
8
|
# CMD
.venv\Scripts\activate
# Power Shell
.venv\Scripts\Activate.ps1
# WSL
source .venv/bin/activate
|
安装Django:
创建Django项目:
1
2
3
|
django-admin startproject EmailProject
cd EmailProject
python manage.py runserver
|
为SMTP配置Django邮件后端
邮件后端是Django发送邮件的机制。默认情况下,Django使用django.core.mail.backends.smtp.EmailBackend。
在EmailProject/settings.py文件底部添加以下设置:
1
2
3
4
5
6
|
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = ''
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = ''
EMAIL_HOST_PASSWORD = ''
|
设置详解
- EMAIL_BACKEND:声明Django项目将用于连接SMTP服务器的后端
- EMAIL_HOST:SMTP服务器域(如smtp.gmail.com)
- EMAIL_PORT:设置为587,这是大多数SMTP服务器的默认端口
- EMAIL_USE_TLS:设置为True,使用传输层安全协议连接SMTP服务器
- EMAIL_HOST_USER:个人电子邮件地址
- EMAIL_HOST_PASSWORD:从电子邮件帐户获取的应用密码
使用应用密码设置Gmail SMTP服务器
步骤1:启用两步验证
- 转到Google帐户:https://myaccount.google.com/
- 在左侧菜单中导航到"安全"
- 滚动到"您如何登录Google"部分
- 单击"两步验证"并按照屏幕说明操作
步骤2:生成应用密码
启用两步验证后,在搜索栏中搜索"应用密码",输入应用密码的名称并单击"创建"。保存显示的16字符应用密码。
使用Django Environ保护邮件后端凭据
在EmailProject目录中创建.env文件:
1
2
|
cd EmailProject/
touch .env
|
在.env文件中添加:
1
2
3
4
|
EMAIL_HOST=smtp.gmail.com
EMAIL_HOST_USER=YourEmail@address
EMAIL_HOST_PASSWORD=YourAppPassword
RECIPIENT_ADDRESS=TheRecieverOfTheMails
|
安装Django-environ:
1
|
pip install django-environ
|
在settings.py文件中使用环境变量:
1
2
3
4
5
6
7
8
9
10
11
12
|
import environ
env = environ.Env()
environ.Env.read_env()
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = env('EMAIL_HOST')
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = env('EMAIL_HOST_USER')
EMAIL_HOST_PASSWORD = env('EMAIL_HOST_PASSWORD')
RECIPIENT_ADDRESS = env('RECIPIENT_ADDRESS')
|
1. 使用Django Shell发送邮件
在shell中:
1
2
3
4
5
6
7
8
|
>>> from django.core.mail import send_mail
>>> from django.conf import settings
>>> send_mail(
... subject='A cool subject',
... message='A stunning message',
... from_email=settings.EMAIL_HOST_USER,
... recipient_list=[settings.RECIPIENT_ADDRESS])
1
|
异步邮件发送
在Django 4.x中支持异步邮件发送:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
import asyncio
from django.core.mail import send_mail
from django.conf import settings
async def send_async_email():
await send_mail(
subject="Async Email Test",
message="This email is sent asynchronously with Django 4.x.",
from_email=settings.EMAIL_HOST_USER,
recipient_list=[settings.RECIPIENT_ADDRESS],
)
asyncio.run(send_async_email())
|
2. 使用Django构建自动化联系表单
创建联系应用
1
|
python manage.py startapp contact
|
在settings.py中安装应用:
1
2
3
4
5
|
INSTALLED_APPS = [
'django.contrib.admin',
# 自定义
'contact',
]
|
联系表单
创建contact/forms.py文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
from django import forms
from django.conf import settings
from django.core.mail import send_mail
class ContactForm(forms.Form):
name = forms.CharField(max_length=120)
email = forms.EmailField()
inquiry = forms.CharField(max_length=70)
message = forms.CharField(widget=forms.Textarea)
def get_info(self):
cl_data = super().clean()
name = cl_data.get('name').strip()
from_email = cl_data.get('email')
subject = cl_data.get('inquiry')
msg = f'{name} with email {from_email} said:'
msg += f'\n"{subject}"\n\n'
msg += cl_data.get('message')
return subject, msg
def send(self):
subject, msg = self.get_info()
send_mail(
subject=subject,
message=msg,
from_email=settings.EMAIL_HOST_USER,
recipient_list=[settings.RECIPIENT_ADDRESS]
)
|
联系视图
contact/views.py:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
from django.views.generic import FormView, TemplateView
from .forms import ContactForm
from django.urls import reverse_lazy
class ContactView(FormView):
template_name = 'contact/contact.html'
form_class = ContactForm
success_url = reverse_lazy('contact:success')
def form_valid(self, form):
form.send()
return super().form_valid(form)
class ContactSuccessView(TemplateView):
template_name = 'contact/success.html'
|
联系URL
创建contact/urls.py:
1
2
3
4
5
6
7
8
9
|
from django.urls import path
from .views import ContactView, ContactSuccessView
app_name = 'contact'
urlpatterns = [
path('', ContactView.as_view(), name="contact"),
path('success/', ContactSuccessView.as_view(), name="success"),
]
|
编写模板
创建模板结构:
1
2
3
|
mkdir -p templates/contact/
cd templates/contact
touch base.html contact.html success.html
|
base.html:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Django Email Send</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0/dist/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>
{% block body %}
{% endblock %}
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
|
安装Django crispy forms:
1
|
pip install django-crispy-forms
|
在settings.py中添加:
1
2
3
4
5
6
7
8
|
INSTALLED_APPS = [
# 第三方应用
'crispy_forms',
# 自定义应用
'contact',
]
CRISPY_TEMPLATE_PACK = 'bootstrap4'
|
contact.html:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
{% extends 'contact/base.html' %}
{% load crispy_forms_tags %}
{% block body %}
<div class="mx-auto my-4 text-center">
<h1>Contact Us</h1>
</div>
<div class="container">
<form action="" method="post">
{% csrf_token %}
{{ form | crispy }}
<button class="btn btn-success my-3" type="submit">Send message</button>
</form>
</div>
{% endblock %}
|
success.html:
1
2
3
4
5
6
7
8
|
{% extends 'contact/base.html' %}
{% block body %}
<div class="mx-auto my-4 text-center">
<h1 class="fw-bolder text-success">We sent your message</h1>
<p class="my-5">You can send another in the <a href="{% url 'contact:contact' %}">contact page</a></p>
</div>
{% endblock %}
|
最佳实践
1. 可重用的邮件发送函数
1
2
3
4
5
6
7
8
9
10
11
12
|
# contact/services.py
from django.core.mail import send_mail
from django.conf import settings
def send_contact_email(subject, message, recipient):
send_mail(
subject=subject,
message=message,
from_email=settings.EMAIL_HOST_USER,
recipient_list=[recipient],
fail_silently=False,
)
|
2. 单元测试
1
2
3
4
5
6
7
8
9
10
11
12
|
from django.test import TestCase
from django.core.mail import send_mail
class EmailTest(TestCase):
def test_email_sending(self):
response = send_mail(
subject='Test Subject',
message='Test Message',
from_email='from@example.com',
recipient_list=['to@example.com'],
)
self.assertEqual(response, 1)
|
3. 发送富HTML邮件
1
2
3
4
5
6
7
8
9
10
11
12
13
|
from django.core.mail import EmailMultiAlternatives
from django.template.loader import render_to_string
from django.conf import settings
def send_html_email():
subject = 'HTML Email Example'
from_email = settings.EMAIL_HOST_USER
recipient = ['recipient@example.com']
html_content = render_to_string('email_template.html', {'key': 'value'})
msg = EmailMultiAlternatives(subject, body='', from_email=from_email, to=recipient)
msg.attach_alternative(html_content, "text/html")
msg.send()
|
4. 集成第三方邮件服务
对于生产就绪的应用程序,考虑使用SendGrid、Mailgun或AWS SES等第三方服务:
1
2
3
|
EMAIL_BACKEND = 'sendgrid_backend.SendgridBackend'
SENDGRID_API_KEY = 'your-api-key'
SENDGRID_SANDBOX_MODE_IN_DEBUG = False
|
5. 用户注册中的邮件验证
1
2
3
4
5
6
7
8
9
10
11
|
from django.core.mail import send_mail
from django.utils.http import urlsafe_base64_encode
from django.utils.encoding import force_bytes
from django.template.loader import render_to_string
def send_verification_email(user, request):
token = account_activation_token.make_token(user)
uid = urlsafe_base64_encode(force_bytes(user.pk))
link = request.build_absolute_uri(f'/activate/{uid}/{token}/')
message = render_to_string('activation_email.html', {'link': link})
send_mail('Verify your email', message, 'from@example.com', [user.email])
|
常见问题解答
可以从Django发送邮件吗?
是的,Django提供了一个内置的邮件发送框架,可以轻松发送邮件。通过在settings.py文件中配置SMTP设置,您可以使用send_mail函数或EmailMessage类发送邮件。
如何在Django中发送邮件?
配置Django发送邮件:
- 在settings.py文件中设置SMTP详细信息
- 如果使用Gmail或类似提供商,使用安全密码而不是主要电子邮件密码
- 对于生产,考虑使用SendGrid、Mailgun或Amazon SES等第三方服务以获得更好的可扩展性
如何测试Django中的邮件发送而不发送真实邮件?
在开发期间,您可以使用可选的邮件后端来测试邮件而不连接到真实的SMTP服务器:
1
|
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
|
对于更高级的测试,使用MailHog或Mailtrap等工具,它们充当假SMTP服务器来捕获和显示测试邮件。
如何安全管理敏感的邮件凭据?
使用Django Environ从.env文件加载敏感凭据:
- 安装Django Environ:
pip install django-environ
- 创建.env文件
- 在settings.py中加载.env文件
总结
恭喜!您已经学会了如何使用Django发送邮件以及如何构建Django联系表单。
有许多方法可以使用Django发送邮件。在本教程中,您使用个人电子邮件地址完成了这一操作,但我希望您探索其他工具并将它们集成到您的项目中。
在本教程中,我们涵盖了以下内容:
- 如何设置Django设置以提供邮件服务
- 如何在小型项目中使用个人电子邮件帐户发送邮件
- 如何在Django项目中使用.env文件处理敏感数据
- 如何构建自动化联系表单