在本教程中,我們將介紹如何使用 Django 發送電子郵件。我們將介紹如何配置 Django SMTP 連接,如何為您的電子郵件提供商設置應用程序密碼,以及如何通過 Django shell 發送電子郵件。我們還將研究如何為您的 Django 應用程序設置聯系表單,這將允許您的客戶與您聯系。
大多數 Web 應用程序使用電子郵件來管理關鍵操作,例如重置密碼、帳戶激活、接收客戶反饋、發送新聞通訊和營銷活動。這些任務中的大多數都需要像SendGrid或Mailgun這樣的專用服務。但是,如果您不希望您的網站獲得大量訪問者,您實際上可以通過您的個人電子郵件提供商完成很多工作。
使用您的個人電子郵件發送電子郵件是小型或測試項目的合理選擇,因此我們將在此處采用這種方法以保持簡單。但是,將您的個人電子郵件服務用于您的生產網站并不是一個好主意。您可以詳細了解Gmail 發送限制,或參考您的電子郵件提供商的限制。
注意:本教程的完整代碼可在GitHub上找到。
了解 SMTP
SMTP(或簡單郵件傳輸協議)是一組用于確定電子郵件如何從發件人傳輸到收件人的規則。SMTP 服務器使用此協議來發送和中繼外發電子郵件。(請注意,其他協議管理電子郵件的接收方式。)
SMTP 服務器始終具有唯一的地址和用于發送消息的特定端口,在大多數情況下為587。我們將看到在使用 Django 發送電子郵件時端口是如何相關的。
由于我們將使用 Gmail,因此我們將使用的地址是smtp.gmail.com,端口是 587。
現在讓我們看看如何使用 Django 發送電子郵件。
創建 Django 項目
每個 Django 項目都應該有一個虛擬環境,因為我們不想弄亂項目依賴項。要創建一個,請運行以下命令:
Python -m venv .venv
注意:如果您不熟悉虛擬環境,請務必查看我們的Python 虛擬環境指南。
上面的命令創建了一個名為 的虛擬環境.venv。要激活此虛擬環境,您可以使用以下命令:
source .venv/bin/activate
由于 Django 是第三方包,你必須用 pip 安裝它:
pip install django
這將安裝最新版本的 Django,您可以使用pip freeze.
要創建 Django 項目,請調用命令行實用程序django-admin:
django-admin startproject EmailProject
使用上面的命令,您正在創建一個名為 的 Django 項目EmailProject,但您可以使用任何您想要的名稱創建該項目。
現在,進入項目目錄并運行服務器:
cd EmailProject
python manage.py runserver
運行 Django 服務器后,在瀏覽器中訪問http://localhost:8000。您將看到一個自動生成的頁面,其中包含最新的 Django 發行說明。
修改設置
您需要在發送電子郵件之前修改設置文件,因此讓我們使用以下命令找到該文件tree:
注意:為簡單起見,我們將僅使用 UNIX(macOS 或 linux)系統命令。
tree
該tree命令輸出目錄的文件結構。在這種情況下,由于我們沒有給它一個特定的目錄路徑,如果我們在項目的根文件夾中,我們將得到類似于以下的內容:
├── EmailProject
│ ├── asgi.py
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
└── manage.py
1 directory, 6 files
我們將在本教程中不斷修改的文件是文件夾中的settings.pyEmailProject。
settings.py包含您需要的所有項目配置,并允許您設置自定義變量。正如 Django 文檔所說,“設置文件只是一個帶有模塊級變量的 Python 模塊”。
讓我們看一下使用 Django 發送電子郵件所需的設置。打開EmailProject/settings.py文件并將以下設置粘貼到文件底部:
# EmailProject/settings.py
# Bottom of the file
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服務器連接。
此變量指向smtp.EmailBackend接收發送電子郵件所需的所有參數的類。我強烈建議您直接在Django 源代碼上查看類構造函數。你會驚訝于這段代碼的可讀性。
注意:雖然這個類是默認的EMAIL_BACKEND,但在 Django 設置中顯式被認為是一個好習慣。
所有其他電子郵件設置將基于此EmailBackend 類的構造函數。
電子郵件主機
該EMAIL_HOST設置指的是您將使用的 SMTP 服務器域。這取決于您的電子郵件提供商。下表列出了與三個常見提供商對應的 SMTP 服務器主機:
電子郵件提供商 |
SMTP 服務器主機 |
Gmail |
smtp.gmail.com |
Outlook/Hotmail |
smtp-mail.outlook.com |
雅虎 |
smtp.mail.yahoo.com |
我們暫時將此設置留空,因為我們稍后將使用.env文件來避免硬編碼敏感密鑰或每個站點的配置。您永遠不應該將憑據直接設置到代碼中。
我們將使用Django Environ來解決這個問題。
電子郵件端口
該EMAIL_PORT設置必須設置為 ,587因為它是大多數 SMTP 服務器的默認端口。對于個人電子郵件提供商而言,情況仍然如此。
此端口與 TLS 加密一起使用,以確保電子郵件發送的安全性。
電子郵件使用 TLS
傳輸層安全(TLS) 是一種跨 Web 使用的安全協議,用于加密 Web 應用程序 (Django) 和服務器 (SMTP 服務器) 之間的通信。
最初,我們將EMAIL_USE_TLS變量設置為True。這意味著 Django 將使用傳輸層安全連接到 SMTP 服務器并發送電子郵件。(對于個人電子郵件提供商,這是強制性的。)
電子郵件主機用戶
該EMAIL_HOST_USER設置是您的個人電子郵件地址。現在將其留空,因為我們將使用它django-environ來設置所有這些憑據。
電子郵件主機密碼
該EMAIL_HOST_PASSWORD設置是您將從您的電子郵件帳戶中獲得的應用密碼 - 我們將在本節之后立即執行此過程。
同樣的故事:將此設置留空,因為我們稍后將使用環境變量。
在 Gmail 中設置應用密碼
要使用該EMAIL_HOST_PASSWORD設置,您需要激活安全性較低的應用訪問權限,并從您的個人電子郵件地址獲得應用密碼。
如果您不激活安全性較低的應用程序訪問權限,您可能會得到一個SMTPAuthenticationError,因為 Django 無法遵守 google 安全協議。
您可以選擇使用普通密碼,但這比使用應用密碼風險更大。我的建議是創建一個新的 Gmail 帳戶或使用“測試”電子郵件地址。
考慮到這一點,您可以通過以下步驟獲取Gmail 應用密碼。請注意,如果您使用的是現有帳戶并啟用了兩步驗證,則可以跳過第 2 步和第 3 步:
- 創建或登錄 Gmail 帳戶
- 轉到myaccount.google.com/lesssecureApps并打開安全性較低的應用程序選項。
- 啟用雙因素身份驗證,因為需要獲取應用密碼。
- 現在您已啟用雙因素身份驗證,是時候獲取應用密碼了。為此,您可以轉到Google 帳戶的安全部分,向下滾動到登錄 Google 部分,然后點擊應用密碼。
在被重定向到應用程序密碼頁面之前,您需要重新提示您的密碼(帳戶密碼)。
進入后,單擊select app,您將為該應用程序密碼選擇一個自定義名稱 - 例如“Django Send Email” - 然后單擊GENERATE。
將顯示一個新窗口,其中包含 16 個字符的密碼。復制它,因為我們需要它來配置我們的 Django 項目。
如果您使用其他電子郵件提供商,請務必閱讀以下指南:
- 雅虎應用密碼
- Outlook 或 Hotmail 應用程序密碼
使用 Django Environ 隱藏敏感鍵
即使您只是在開發中發送電子郵件,也不應該將密碼直接寫入源代碼。當使用版本控制系統和 GitHub 來托管您的項目時,這一點變得更加重要。您不希望人們訪問您的數據。
讓我們看看如何通過使用Django-environ來防止這種情況發生。
使用以下命令.env在EmailProject目錄(settings.py文件所在的位置)內創建一個文件:
cd EmailProject/
ls
settings.py # The settings file must be here
touch .env
現在,打開該.env文件并輸入以下鍵值對:
EMAIL_HOST=smtp.gmail.com
EMAIL_HOST_USER=YourEmail@address
EMAIL_HOST_PASSWORD=YourAppPassword
RECIPIENT_ADDRESS=TheRecieverOfTheMails
分解此文件的內容:
- EMAIL_HOST:您的電子郵件提供商 SMTP 服務器地址。請參閱上面的電子郵件主機表以獲取快速指導。在本例中,我使用的smtp.gmail.com是 Gmail SMTP 地址。
- EMAIL_HOST_USER: 您的電子郵件地址。
- EMAIL_HOST_PASSWORD:您剛剛生成的應用密碼。請記住,它不包含任何空格。
- RECIPIENT_ADDRESS:您將收到郵件的電子郵件地址。這是我們稍后將創建的自定義設置,用于將所有電子郵件發送給同一收件人。
要使用這些環境變量,我們需要安裝Django-environ:
pip install django-environ
注意:確保您的虛擬環境已激活。
現在,打開settings.py位于EmailProject目錄中的 并使用以下代碼:
# EmailProject/settings.py
# This should be at the start of the file
import environ
env = environ.Env()
environ.Env.read_env()
# Previous settings ...
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')
# Custom setting. To email
RECIPIENT_ADDRESS = env('RECIPIENT_ADDRESS')
首先,我們在environ設置文件的頂部導入包。請記住,所有導入都應在開頭。
然后我們創建一個env變量,該變量將包含.env.
該env('KEY')語句意味著我們正在查找該鍵的值。確保.env在繼續之前設置了文件,因為如果ImproperlyConfigured未設置某些環境變量,您將收到 Django錯誤。
請注意,這RECIPIENT_ADDRESS是一個自定義設置,我們將使用它來將電子郵件發送到我們可以訪問的地址。
如果您使用 Git 和 GitHub .env,請不要忘記在.gitignore中包含該文件。您只需打開它并添加以下行即可完成此操作:
.env
1. 使用 Django Shell 發送電子郵件
最后,我們進入了文章的精彩部分!是時候向 Django 發送您的第一封電子郵件了。
打開終端,激活虛擬環境,然后運行:
python manage.py shell
這將創建一個 shell,其中包含已為我們配置的所有 Django 設置。在那個全新的 shell 中,粘貼以下代碼:
>>> 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
我們也可以在不指定參數的情況下制作單行:
>>> send_mail('A cool subject', 'A stunning message', settings.EMAIL_HOST_USER, [settings.RECIPIENT_ADDRESS])
1
讓我們分解上面的代碼:
- 我們導入 Django send_mail函數。
- 然后我們導入settings包含所有全局設置和每個站點設置(settings.py文件內的設置)的對象。
- 最后,我們將所有需要的參數傳遞給send_mail函數。此函數返回發送的電子郵件數量,在本例中為1。
請注意我們如何使用settings對象來獲取from_email(您用來發送電子郵件的電子郵件)和recipient_list(RECIPIENT_ADDRESS我們在 中定義的自定義設置.env)。
現在,如果我檢查我的收件箱——當我將RECIPIENT_ADDRESS環境變量設置為我的電子郵件地址時——我將收到 Django 發送的消息。
2. 使用 Django 構建自動聯系表單
在本節中,我們將使用 Django 表單和內置send_mail函數構建一個自動聯系表單。此外,我們將send()在聯系表單中創建一個自定義函數 ,以便在視圖中更容易實現它。
讓我們從創建聯系人應用程序開始。進入項目根目錄——所在manage.py的位置——并運行:
python manage.py startapp contact
然后,將其安裝在文件INSTALLED_APPS內的變量中EmailProject/settings.py:
# EmailProject/settings.py
INSTALLED_APPS = [
'django.contrib.admin',
...
# Custom
'contact',
]
在推進contact應用程序之前,讓我們配置文件的urlpatterns內部EmailProject/urls.py。為此,請導入該django.urls.include函數并在整個項目中包含聯系人 URL。別擔心;我們稍后將配置聯系人 URL:
# EmailProject/urls.py
from django.contrib import admin
from django.urls import path, include # New import
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('contact.urls')) # Include Contact URLs
]
聯系表
進入contact應用程序文件夾并創建一個forms.py文件。在forms.py文件中定義所有表單是一種很好的做法,但這不是強制性的。這就是 Django 默認不包含這個文件的原因。
您可以使用以下命令創建表單文件:
cd ../contact/
# You were inside the EmailProject folder
touch forms.py
打開您剛剛創建的文件并進行以下導入:
# contact/forms.py
from django import forms
from django.conf import settings
from django.core.mail import send_mail
Django表單模塊為我們提供了創建聯系表單所需的所有類和字段。我們再次導入settings對象和send_mail發送電子郵件的函數。
我們的聯系表單將包含多個字段并使用兩種自定義方法:get_info(),用于格式化用戶提供的信息,以及send(),將發送消息。
讓我們看看這在代碼中的實現:
# contact/forms.py
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):
"""
Method that returns formatted information
:return: subject, msg
"""
# Cleaned data
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}"nn'
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]
)
這是一個巨大的類,所以讓我們分解我們在每個部分中所做的事情。首先,我們定義了發送消息所需的四個字段:
- name和enquiry是表示聯系消息的名稱和原因的CharFields。
- email是一個EmailField,代表試圖與您聯系的人的電子郵件。考慮到電子郵件不會由用戶的電子郵件地址發送,而是由您在 Django 項目中設置的發送電子郵件的電子郵件地址發送。
- message是另一個CharField例外,我們使用的是Textarea小部件。這意味著,當顯示表單時,它將呈現一個<textarea>標簽而不是一個簡單的<input>.
進入自定義方法,我們只使用該get_info方法來格式化用戶提供的信息并返回兩個變量:subject,它只是inquiry字段,以及message,它將是 Django 發送的實際消息。
另一方面,該send()方法僅從函數中獲取格式化信息get_info并發送消息send_mail。
盡管本節非常大,但您將看到我們如何通過將所有發送邏輯實現到ContactForm自身來簡化聯系人視圖。
聯系人視圖
打開contact/views.py文件并添加以下導入:
# contact/views.py
from django.views.generic import FormView, TemplateView
from .forms import ContactForm
from django.urls import reverse_lazy
如您所見,我們將使用Django 通用視圖,這在執行簡單任務時為我們節省了大量時間——例如,在FormView使用TemplateView.
此外,我們正在導入ContactForm我們在上一節中構建的 以及在使用基于類的視圖時使用的reverse_lazy函數。
繼續查看視圖,讓我們編寫ContactView:
# contact/views.py
class ContactView(FormView):
template_name = 'contact/contact.html'
form_class = ContactForm
success_url = reverse_lazy('contact:success')
def form_valid(self, form):
# Calls the custom send method
form.send()
return super().form_valid(form)
如您所見,我們正在使用我們創建的構建一個簡單的FormViewContactForm。我們也在設置template_name和success_url。我們稍后將編寫 HTML 模板并設置 URL。
該形式有效的方法,讓我們用發送電子郵件ContactForm.send()只有在形式的所有字段都是有效的方法。這意味著如果用戶輸入無效的輸入——例如未格式化的電子郵件地址——消息將不會被發送。
form_valid在基于函數的視圖中,上述方法實現將等效于以下內容:
# Previous function based contact_view ...
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
form.send()
return redirect('contact:success')
else:
form = ContactForm())
在本節結束時,我們將編寫一個ContactSucessView,它將向用戶顯示一條成功消息。由于我們已經導入了TemplateView類,我們只需要繼承它并定義template_name屬性:
# contact/views.py
class ContactSuccessView(TemplateView):
template_name = 'contact/success.html'
如果您有任何疑問,可以查看GitHub 存儲庫views.py上的文件。
聯系網址
是時候創建contact應用程序的 URL 模式了。由于 Djangourls.py默認不給我們文件,我們需要使用以下命令創建它(確保在contactapp 文件夾中):
pwd
# /path/to/project/EmailProject/contact
touch urls.py
打開該文件并設置app_name和urlpatterns變量:
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"),
]
我們使用路徑將路由及其對應視圖包含到應用程序的 URL 配置中。當我們將app_name變量設置為 時'contact',這意味著應用程序的 URL命名空間將如下所示:
contact:name_of_path
# For ContactView
contact:contact
# For ContactSuccessView
contact:success
注意:命名空間是我們在 Django 模板和視圖中動態調用的 URL。
您可以在官方文檔中了解有關 Django URL 調度程序的更多信息。
編寫模板
Django 模板是動態顯示數據的首選方式,使用HTML和 Django 模板語言給我們的特殊標簽。
對于這個特定的應用程序,我們將使用三個模板:
- base.html: 所有其他模板都將從它繼承。它將包含所有模板必須具有的所有 HTML 框架,以及指向 Bootstrap 的鏈接。
- contact.html:顯示聯系表格。
- success.html: 顯示成功消息。
讓我們從創建聯系人的應用程序模板結構開始(確保您在聯系人應用程序文件夾中):
mkdir -p templates/contact/
cd templates/contact
touch base.html contact.html success.html
上面的命令創建了可重用 Django 應用程序的典型模板結構appname/templates/appname——以及我之前提到的樹模板文件。
應用程序文件結構現在應該如下所示:
.
├── admin.py
├── apps.py
├── forms.py
├── __init__.py
├── migrations
│ └── __init__.py
├── models.py
├── templates
│ └── contact
│ ├── base.html
│ ├── contact.html
│ └── success.html
├── tests.py
├── urls.py
└── views.py
讓我們進入base.html模板的內容:
<!-- contact/templates/contact/base.html -->
<!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"
integrity="sha384-wEmeIV1mKuiNpC+IOBjI7aAzPcEZeedi5yW5f2yOq55WWLwNGmvvx4Um1vskeMj0" crossorigin="anonymous" />
</head>
<body>
{% block body %}
{% endblock %}
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0/dist/js/bootstrap.bundle.min.js"
integrity="sha384-p34f1UUtsS3wqzfto5wAAmdvj+osOnFyQFpp4Ua3gs/ZVWx6oOypYoCJhGGScy+8" crossorigin="anonymous">
</script>
</body>
</html>
如您所見,它是包含Bootstrap 5鏈接的 HTML 文件的簡單框架。這允許我們在不使用 CSS 文件的情況下對我們的聯系人應用程序進行風格化。
該{% block name-of-block %}標簽允許我們設置一個“子模板”將使用的占位符。使用此標記使模板繼承成為一項簡單的任務。
在進入表單之前,您需要安裝Django 脆皮表單包,它允許我們輕松地對它們進行樣式化:
pip install django-crispy-forms
再一次,crispy_forms是一個 Django 應用程序,我們需要將它包含在INSTALLED_APPS列表中:
# config/settings.py
INSTALLED_APPS = [
...
# 3rd party apps
'crispy_forms',
# Custom apps
'contact',
]
# Indicates the frontend framework django crispy forms use
CRISPY_TEMPLATE_PACK = 'bootstrap4'
我們使用 Bootstrap 4 的模板包,因為 Bootstrap 表單類在第 4 版和第 5 版之間兼容(在撰寫本文時)。
現在,讓我們處理contact.html模板:
<!-- contact/templates/contact/contact.html -->
{% 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 %}
請注意我們如何擴展基本模板并使用塊占位符。這就是 Django 模板語言如此高效的原因,因為它讓我們節省了大量的 HTML 復制和粘貼。
談到表單,我們使用了方法"post",這意味著我們ContactView將處理用戶提供的數據,如果表單有效,我們將發送電子郵件。
的{% csrf_token %}是,由于安全原因,所有形式的強制性。Django 的文檔有一個關于CSRF 令牌的專用頁面以及在處理表單時使用它們的原因。
我們將使用crispy模板標簽渲染表單,這就是為什么我們用{% load crispy_forms_tags %}.
最后,讓我們編寫success.html模板:
{% 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 %}
如您所見,這是一個簡單的成功公告,其中包含指向聯系表單的鏈接,以防用戶想要發送另一條消息。
讓我們再次運行服務器并訪問http://localhost:8000(確保您已.venv激活并且您在項目根文件夾中):
python manage.py runserver
下圖顯示了最終聯系表格的樣子。
這是成功消息的圖像。
這是收件箱中電子郵件的圖像。
包起來
恭喜!您已經學習了如何使用 Django 發送電子郵件以及如何構建 Django 聯系表單。
使用 Django 發送電子郵件的方法有很多種。在本教程中,您已使用個人電子郵件地址完成此操作,但我希望您探索其他工具并將它們集成到您的項目中。
在本教程中,我們介紹了以下內容:
- 如何設置 Django 設置以提供電子郵件
- 小項目中如何使用個人郵箱發送郵件
- 如何.env在 Django 項目中使用文件來使用敏感數據
- 如何構建自動聯系表單