09-1. SMTP 協定:郵件發送協定
深入理解 SMTP 郵件傳輸機制與安全驗證
目錄
📧 SMTP 協定:郵件發送協定
⏱️ 閱讀時間: 10 分鐘 🎯 難度: ⭐⭐ (中等)
🏗️ SMTP 在網路模型中的位置
OSI 7 層模型
┌──────────────────────────────┬─────────────────────────┐
│ 7. Application Layer (應用層) │ SMTP (郵件發送) │ ← SMTP 在這裡
├──────────────────────────────┼─────────────────────────┤
│ 6. Presentation Layer (表示層)│ MIME, SSL/TLS │
├──────────────────────────────┼─────────────────────────┤
│ 5. Session Layer (會話層) │ 建立、維護會話 │
├──────────────────────────────┼─────────────────────────┤
│ 4. Transport Layer (傳輸層) │ TCP │
├──────────────────────────────┼─────────────────────────┤
│ 3. Network Layer (網路層) │ IP │
├──────────────────────────────┼─────────────────────────┤
│ 2. Data Link Layer (資料鏈結層)│ Ethernet │
├──────────────────────────────┼─────────────────────────┤
│ 1. Physical Layer (實體層) │ 網路線、光纖 │
└──────────────────────────────┴─────────────────────────┘SMTP 位於第 7 層(應用層)
- SMTP 是應用層協定
- 負責郵件的「發送」與「轉發」
- MIME 在表示層處理附件編碼
TCP/IP 4 層模型
┌─────────────────────────────┬─────────────────────────┐
│ 4. Application Layer (應用層) │ SMTP (郵件發送) │ ← SMTP 在這裡
├─────────────────────────────┼─────────────────────────┤
│ 3. Transport Layer (傳輸層) │ TCP │
├─────────────────────────────┼─────────────────────────┤
│ 2. Internet Layer (網際網路層)│ IP │
├─────────────────────────────┼─────────────────────────┤
│ 1. Network Access (網路存取層)│ Ethernet │
└─────────────────────────────┴─────────────────────────┘SMTP 位於第 4 層(應用層)
- 在 TCP/IP 模型中,SMTP 是應用層協定
- 使用 TCP 提供可靠傳輸
- 使用 Port 25、587、465
重點:
- SMTP 是應用層協定(兩種模型都是)
- 使用 TCP(可靠傳輸,不能丟失郵件)
- SMTP 專門負責「發送」郵件(發送方 → 伺服器 → 接收方伺服器)
- 現代使用 SSL/TLS 加密(SMTPS)
- 接收郵件則使用其他協定(POP3、IMAP,詳見 09-2 和 09-3)
為什麼電子郵件使用 TCP?
郵件傳輸的需求:
1. 可靠性 ✅
郵件不能丟失
TCP 保證送達
2. 順序性 ✅
郵件內容必須完整
TCP 保證順序
3. 連線導向 ✅
SMTP 需要會話(HELO → MAIL FROM → RCPT TO → DATA)
TCP 提供持久連線
UDP 不適合:
❌ 不可靠(郵件可能丟失)
❌ 無順序保證(內容可能錯亂)
❌ 無連線狀態(無法進行 SMTP 會話)📜 歷史:為什麼電子郵件不用 HTTP?
時間線比較 ⭐⭐⭐
電子郵件比網頁早得多!
1971 年 📧 第一封電子郵件
└─ Ray Tomlinson 發明 @ 符號
發送第一封網路郵件
1982 年 📮 SMTP 協定誕生
└─ RFC 821 定義
電子郵件系統已經成熟運作
1984 年 📬 POP 協定誕生
└─ RFC 918(POP1)
可以從遠端伺服器取信
1988 年 📪 IMAP 協定誕生
└─ RFC 1064(IMAP1)
可以在伺服器上管理郵件
1989 年 🌐 HTTP 才被發明
└─ Tim Berners-Lee 在 CERN
為了分享研究文件
1991 年 🌍 全球資訊網 (WWW) 誕生
└─ 第一個網頁瀏覽器
HTTP 開始普及
1993 年 📪 IMAP4 (現代版本)
└─ RFC 1730
我們現在用的版本
1996 年 📮 SMTP 擴展
└─ RFC 1869(ESMTP)
支援認證、大小限制等重點:
電子郵件系統(SMTP/POP/IMAP)
↓
比 HTTP 早了將近 20 年!
↓
所以不是「為什麼不用 HTTP」
而是「HTTP 出現時,電子郵件系統已經運作十幾年了」為什麼不換成 HTTP?
即使 HTTP 後來變流行,電子郵件也沒換的原因:
1️⃣ 已有龐大基礎設施
全球數十億個郵件伺服器
都使用 SMTP/POP3/IMAP
→ 換掉成本太高
2️⃣ 設計目的不同
HTTP:請求/回應(拿網頁)
- 客戶端主動請求
- 伺服器被動回應
- 無狀態
SMTP:推送(寄信)
- 發送方主動推送
- 接收方被動接收
- 需要持久連線
3️⃣ 郵件需要「推送」機制
範例:
Alice 寄信給 Bob
用 SMTP:
Alice Server → 主動推送 → Bob Server
→ Bob Server 收到後儲存
→ Bob 隨時可以取信
如果用 HTTP:
Alice Server → ? → Bob Server
→ Bob Server 怎麼知道有新信?
→ 需要不斷輪詢(Polling)?
→ 非常沒效率!
4️⃣ 郵件轉發路徑
alice@gmail.com → bob@yahoo.com
SMTP:
Gmail Server → Yahoo Server
→ 直接伺服器對伺服器推送
HTTP:
沒有「伺服器主動推送」機制
→ 需要額外設計
5️⃣ 相容性考量
全球數百萬個組織使用電子郵件
- 公司內部郵件伺服器
- ISP 郵件服務
- 免費郵件服務(Gmail、Outlook)
全部改成 HTTP?
→ 成本天文數字
→ 過渡期間會一團混亂現代的融合:Webmail
雖然底層仍用 SMTP/IMAP,但使用者介面已經變成 HTTP!
傳統郵件客戶端(Outlook、Thunderbird):
使用者 ↔ SMTP/IMAP ↔ 郵件伺服器
現代 Webmail(Gmail、Outlook.com):
使用者 ↔ HTTP/HTTPS ↔ 網頁伺服器 ↔ SMTP/IMAP ↔ 郵件伺服器
└── 你看到的 ──┘ └── 背後的 ──┘
Gmail 架構:
1. 你開啟 gmail.com(HTTP)
2. 網頁顯示收件匣(HTTP 拿資料)
3. 你按「寄信」(HTTP 送出)
4. Gmail Server 用 SMTP 真正寄出
5. 對方 Server 用 SMTP 接收
6. 對方用 IMAP/HTTP 讀取
結論:
前端:HTTP(方便、好看)
後端:SMTP/IMAP(標準、可靠)
→ 兩全其美!🎯 電子郵件系統概覽
💡 比喻:傳統郵局系統
發送郵件:
你 → 郵局(SMTP)→ 對方郵局 → 對方信箱
接收郵件:
對方信箱 → 你取信(POP3 或 IMAP)→ 你閱讀電子郵件協定分工:
| 協定 | 功能 | Port | 比喻 | 說明 |
|---|---|---|---|---|
| SMTP | 發送郵件 | 25, 587, 465 | 寄信 📮 | 本篇重點 |
| POP3 | 下載郵件 | 110, 995 | 取信(帶走) 📬 | 詳見 09-2 |
| IMAP | 同步郵件 | 143, 993 | 查信(留在郵局) 📪 | 詳見 09-3 |
SMTP 的角色:
- 專門負責「發送」:從發送方到收件方伺服器
- 伺服器間轉發:將郵件從一個郵件伺服器傳遞到另一個
- 不處理接收:接收郵件由 POP3 或 IMAP 負責
🔍 SMTP 核心概念 ⭐⭐⭐
簡單記憶法
SMTP = Simple Mail Transfer Protocol
= 簡單郵件傳輸協定
= 只負責「寄信」這一件事SMTP 工作流程
場景:Alice 寄信給 Bob
第 1 步:Alice 發送(客戶端 → 伺服器)
Alice 的郵件客戶端 → SMTP → smtp.alice.com
「我要寄信給 bob@example.com」
第 2 步:查詢收件者伺服器(DNS 查詢)
smtp.alice.com → DNS 查詢
「example.com 的郵件伺服器在哪?」
← 回應:mail.example.com
第 3 步:伺服器轉發(伺服器 → 伺服器)
smtp.alice.com → SMTP → mail.example.com
「這封信給 bob@example.com」
第 4 步:儲存到收件匣
mail.example.com → 儲存到 Bob 的信箱
第 5 步:Bob 收信(使用 POP3 或 IMAP)
Bob 的郵件客戶端 → POP3/IMAP → mail.example.com
「下載/同步我的郵件」記憶口訣
SMTP:Simple Mail Transfer Protocol
→ 「傳送郵件」
→ 只負責「寄」
→ Port 25(傳統)/ 587(STARTTLS)/ 465(SSL)
核心功能:
✉️ 發送:客戶端 → 伺服器
🔄 轉發:伺服器 → 伺服器
📮 投遞:最終送達收件伺服器📮 SMTP(Simple Mail Transfer Protocol)
💡 功能:發送電子郵件
就像把信投進郵筒,郵局負責送達SMTP 運作流程
Alice SMTP Server (alice.com) SMTP Server (bob.com) Bob
│ │ │ │
├─ MAIL FROM ─────────────>│ │ │
│ alice@alice.com │ │ │
│ │ │ │
├─ RCPT TO ───────────────>│ │ │
│ bob@bob.com │ │ │
│ │ │ │
├─ DATA ──────────────────>│ │ │
│ (郵件內容) │ │ │
│ │ │ │
│ ├─ 查詢 MX 記錄 ────────> DNS │
│ │<─ bob.com MX: mail.bob.com ───────────────┤
│ │ │ │
│ ├─ MAIL FROM ────────────>│ │
│ ├─ RCPT TO ──────────────>│ │
│ ├─ DATA ─────────────────>│ │
│ │ │ │
│ │ ├─ 儲存到信箱 ──>│SMTP 命令
HELO/EHLO - 打招呼
MAIL FROM - 寄件者
RCPT TO - 收件者
DATA - 郵件內容
QUIT - 結束連線SMTP 會話範例
S: 220 mail.example.com SMTP服務就緒
C: EHLO client.example.com
S: 250-mail.example.com
S: 250-SIZE 52428800
S: 250 STARTTLS
C: MAIL FROM:<alice@example.com>
S: 250 OK
C: RCPT TO:<bob@example.com>
S: 250 OK
C: DATA
S: 354 開始輸入郵件內容,以 . 結束
C: From: Alice <alice@example.com>
C: To: Bob <bob@example.com>
C: Subject: 測試郵件
C:
C: 這是測試內容。
C: .
S: 250 郵件已接受
C: QUIT
S: 221 再見Python 發送郵件(SMTP)
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
# 建立郵件
msg = MIMEMultipart()
msg['From'] = 'alice@example.com'
msg['To'] = 'bob@example.com'
msg['Subject'] = 'Python 測試郵件'
# 郵件內容
body = '這是使用 Python 發送的測試郵件'
msg.attach(MIMEText(body, 'plain'))
# 連線到 SMTP 伺服器
try:
# 使用 TLS(Port 587)
server = smtplib.SMTP('smtp.gmail.com', 587)
server.starttls() # 啟用 TLS 加密
# 登入
server.login('alice@gmail.com', 'password')
# 發送郵件
text = msg.as_string()
server.sendmail('alice@gmail.com', 'bob@example.com', text)
print('郵件發送成功')
except Exception as e:
print(f'發送失敗:{e}')
finally:
server.quit()發送 HTML 郵件
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
msg = MIMEMultipart('alternative')
msg['Subject'] = 'HTML 郵件測試'
msg['From'] = 'alice@example.com'
msg['To'] = 'bob@example.com'
# 純文字版本(備用)
text = "這是純文字內容"
# HTML 版本
html = """\
<html>
<head></head>
<body>
<h1>Hello!</h1>
<p>這是 <b>HTML</b> 郵件</p>
<a href="https://example.com">點我</a>
</body>
</html>
"""
# 附加兩種格式(郵件客戶端會選擇 HTML)
msg.attach(MIMEText(text, 'plain'))
msg.attach(MIMEText(html, 'html'))
# 發送
server.sendmail('alice@example.com', 'bob@example.com', msg.as_string())發送附件
from email.mime.base import MIMEBase
from email import encoders
msg = MIMEMultipart()
msg['From'] = 'alice@example.com'
msg['To'] = 'bob@example.com'
msg['Subject'] = '附件測試'
# 郵件內容
msg.attach(MIMEText('請查收附件', 'plain'))
# 讀取檔案
filename = 'document.pdf'
with open(filename, 'rb') as attachment:
# MIMEBase 表示二進位資料
part = MIMEBase('application', 'octet-stream')
part.set_payload(attachment.read())
# 編碼為 Base64
encoders.encode_base64(part)
# 新增 Header
part.add_header(
'Content-Disposition',
f'attachment; filename= {filename}'
)
# 附加到郵件
msg.attach(part)
# 發送
server.sendmail('alice@example.com', 'bob@example.com', msg.as_string())🔐 郵件安全
1. TLS/SSL 加密
Port 對照:
| 協定 | 明文 Port | 加密 Port | 加密方式 |
|---|---|---|---|
| SMTP | 25 | 587 (STARTTLS), 465 (SSL) | TLS |
| POP3 | 110 | 995 | SSL |
| IMAP | 143 | 993 | SSL |
STARTTLS vs SSL:
STARTTLS(Port 587):
1. 建立明文連線
2. 發送 STARTTLS 命令
3. 升級為 TLS 加密連線
SSL(Port 465/995/993):
1. 直接建立 SSL 加密連線Python 使用 TLS:
# SMTP with STARTTLS
server = smtplib.SMTP('smtp.gmail.com', 587)
server.starttls() # 升級為 TLS
server.login('user', 'pass')
# SMTP with SSL
server = smtplib.SMTP_SSL('smtp.gmail.com', 465)
server.login('user', 'pass')
# IMAP with SSL
imap = imaplib.IMAP4_SSL('imap.gmail.com', 993)
imap.login('user', 'pass')2. SPF(Sender Policy Framework)
💡 功能:防止郵件偽造
檢查「發信 IP」是否被授權代表該域名發信SPF 記錄(DNS TXT):
example.com. IN TXT "v=spf1 ip4:1.2.3.4 include:_spf.google.com ~all"
│ │ │ │
│ │ │ └─ 其他:Soft Fail
│ │ └───────────────────────── 包含 Google SPF
│ └────────────────────────────────────── 允許 IP 1.2.3.4
└───────────────────────────────────────────── SPF 版本SPF 機制:
+all - 允許所有(不建議)
-all - 拒絕所有(嚴格)
~all - Soft Fail(建議)
?all - 中立
ip4:1.2.3.4 - 允許特定 IPv4
ip6:2001:db8::1 - 允許特定 IPv6
include:domain.com - 包含其他域名的 SPF
a - 允許 A 記錄的 IP
mx - 允許 MX 記錄的 IP檢查 SPF:
# 查詢 SPF 記錄
dig example.com TXT
# 測試郵件來源
# 收件伺服器會檢查:
# 1. 從 IP 1.2.3.4 收到郵件
# 2. 聲稱來自 alice@example.com
# 3. 查詢 example.com 的 SPF 記錄
# 4. 檢查 1.2.3.4 是否在允許列表
# 5. 通過 → Accept,失敗 → Reject/Flag3. DKIM(DomainKeys Identified Mail)
💡 功能:數位簽章
證明郵件確實來自聲稱的域名,且未被竄改運作原理:
發送方:
1. 用私鑰簽署郵件
2. 在 Header 加入 DKIM-Signature
接收方:
1. 從 Header 取得簽章
2. 查詢 DNS 取得公鑰
3. 驗證簽章
4. 通過 → 可信任DKIM 簽章(郵件 Header):
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=example.com; s=default;
h=from:to:subject;
bh=abc123...;
b=xyz789...DKIM 公鑰(DNS TXT):
default._domainkey.example.com. IN TXT "v=DKIM1; k=rsa; p=MIGfMA0GCS..."
│ │ │ │ │ │
│ │ │ │ │ └─ 公鑰(Base64)
│ │ │ │ └──────── 金鑰類型(RSA)
│ │ │ └──────────────── DKIM 版本
│ │ └───────────────────────────────────────── 域名
│ └──────────────────────────────────────────────────── 選擇器
└──────────────────────────────────────────────────────────── 固定前綴4. DMARC(Domain-based Message Authentication, Reporting & Conformance)
💡 功能:整合 SPF 和 DKIM
定義「如果驗證失敗該怎麼辦」DMARC 記錄:
_dmarc.example.com. IN TXT "v=DMARC1; p=reject; rua=mailto:dmarc@example.com"
│ │ │
│ │ └─ 回報郵件地址
│ └────────── 政策:reject(拒絕)
└──────────────────── DMARC 版本政策選項:
p=none - 不處理(僅監控)
p=quarantine - 隔離(標記為垃圾郵件)
p=reject - 拒絕(不接收)驗證流程:
收到郵件 → 檢查 SPF → 檢查 DKIM → 查詢 DMARC 政策
SPF Pass + DKIM Pass → Accept
SPF Fail + DKIM Fail → 依 DMARC 政策處理(none/quarantine/reject)🎓 常見面試題
Q1:SMTP 的工作流程是什麼?
答案:
完整流程:
1. 客戶端連線到 SMTP 伺服器
- Port 587 (STARTTLS) 或 465 (SSL)
2. 伺服器回應就緒訊息
S: 220 smtp.example.com SMTP Ready
3. 客戶端問候 (EHLO)
C: EHLO client.example.com
S: 250-smtp.example.com
S: 250-SIZE 52428800
S: 250 STARTTLS
4. 啟用 TLS 加密 (如果用 Port 587)
C: STARTTLS
S: 220 Ready to start TLS
5. 認證 (AUTH)
C: AUTH LOGIN
C: <Base64 encoded username>
C: <Base64 encoded password>
S: 235 Authentication successful
6. 指定寄件者 (MAIL FROM)
C: MAIL FROM:<alice@example.com>
S: 250 OK
7. 指定收件者 (RCPT TO)
C: RCPT TO:<bob@example.com>
S: 250 OK
8. 發送郵件內容 (DATA)
C: DATA
S: 354 Start mail input
C: From: Alice <alice@example.com>
C: To: Bob <bob@example.com>
C: Subject: Test
C:
C: Mail content here.
C: .
S: 250 Message accepted
9. 結束連線 (QUIT)
C: QUIT
S: 221 ByePython 實作:
import smtplib
# 連線並發送
server = smtplib.SMTP('smtp.gmail.com', 587)
server.starttls() # 啟用 TLS
server.login('user@gmail.com', 'password')
server.sendmail(from_addr, to_addr, msg)
server.quit()記憶技巧:
連線 → 問候 (EHLO) → 加密 (STARTTLS) → 認證 (AUTH)
→ 寄件者 (MAIL FROM) → 收件者 (RCPT TO)
→ 內容 (DATA) → 結束 (QUIT)Q2:為什麼需要 SPF/DKIM/DMARC?
答案:
問題:郵件偽造(Email Spoofing)
攻擊者可以偽造 From:
From: ceo@yourcompany.com
實際從 attacker.com 的伺服器發送
接收者看到:CEO 發來的郵件
實際上:釣魚郵件解決方案:
1. SPF(發送者 IP 驗證):
檢查:發信 IP 是否被授權?
example.com 的 SPF:
v=spf1 ip4:1.2.3.4 -all
如果郵件從 5.6.7.8 發送:
→ SPF Fail(IP 不在允許列表)2. DKIM(內容簽章):
檢查:郵件是否被竄改?
發送者用私鑰簽署郵件
接收者用公鑰驗證簽章
如果簽章不符:
→ DKIM Fail(郵件被竄改或偽造)3. DMARC(整合政策):
檢查:SPF 或 DKIM 失敗時該怎麼辦?
DMARC 政策:p=reject
如果 SPF Fail 且 DKIM Fail:
→ 拒絕郵件(不進收件匣)三者關係:
SPF:「你是誰?」(驗證發送者身份)
DKIM:「內容對嗎?」(驗證郵件完整性)
DMARC:「失敗怎麼辦?」(執行政策)Q3:如何防止郵件被標記為垃圾郵件?
答案:
多層防護:
1. 設定 SPF/DKIM/DMARC:
# SPF
example.com. IN TXT "v=spf1 include:_spf.google.com ~all"
# DKIM
# 使用郵件服務商提供的 DKIM 設定
# DMARC
_dmarc.example.com. IN TXT "v=DMARC1; p=quarantine; rua=mailto:dmarc@example.com"2. 反向 DNS(PTR 記錄):
# 確保發送 IP 有反向 DNS
dig -x 1.2.3.4
# 應該回應你的域名
1.2.3.4.in-addr.arpa. IN PTR mail.example.com.3. 避免垃圾郵件特徵:
# ❌ 不好的做法
subject = "!!!免費贈送!!! 點擊這裡 $$$" # 過多特殊符號
body = "BUY NOW" * 100 # 重複內容
from_ = "noreply@randomdomain.xyz" # 可疑域名
# ✅ 好的做法
subject = "您的訂單確認"
body = "親愛的客戶,您的訂單已確認..."
from_ = "support@example.com"4. 驗證發送頻率:
# 避免短時間大量發送
import time
for recipient in recipients:
send_email(recipient)
time.sleep(1) # 間隔 1 秒5. 提供取消訂閱連結:
<!-- 郵件底部 -->
<p>
如不想收到此類郵件,請
<a href="https://example.com/unsubscribe?email=user@example.com">取消訂閱</a>
</p>6. 使用專業郵件服務:
SendGrid、MailGun、AWS SES
這些服務已幫你處理:
- IP 信譽維護
- SPF/DKIM 自動設定
- 退信處理
- 垃圾郵件監控Q4:如何處理大量郵件發送?
答案:
使用郵件佇列系統:
# 使用 Celery + Redis
from celery import Celery
app = Celery('tasks', broker='redis://localhost:6379/0')
@app.task
def send_email_task(to, subject, body):
"""非同步發送郵件"""
try:
server = smtplib.SMTP_SSL('smtp.gmail.com', 465)
server.login('user@gmail.com', 'password')
msg = MIMEText(body)
msg['Subject'] = subject
msg['From'] = 'user@gmail.com'
msg['To'] = to
server.send_message(msg)
server.quit()
return f"郵件已發送給 {to}"
except Exception as e:
# 失敗重試
raise self.retry(exc=e, countdown=60)
# 使用
for user in users:
send_email_task.delay(user.email, '通知', '內容')
# .delay() 將任務加入佇列,立即返回批次發送策略:
import time
def send_bulk_emails(recipients, subject, body, batch_size=100):
"""批次發送,避免被限制"""
for i in range(0, len(recipients), batch_size):
batch = recipients[i:i + batch_size]
for recipient in batch:
send_email(recipient, subject, body)
# 每批次後休息
if i + batch_size < len(recipients):
print(f"已發送 {i + batch_size} 封,休息 60 秒...")
time.sleep(60)
# 使用
send_bulk_emails(all_users, '月報', '內容', batch_size=50)使用專業服務(SendGrid):
import sendgrid
from sendgrid.helpers.mail import Mail, Email, To, Content
sg = sendgrid.SendGridAPIClient(api_key='YOUR_API_KEY')
# 單封郵件
message = Mail(
from_email='from@example.com',
to_emails='to@example.com',
subject='Sending with SendGrid',
html_content='<strong>Hello</strong>'
)
response = sg.send(message)
# 批次發送(使用範本)
for user in users:
message = Mail(
from_email='from@example.com',
to_emails=user.email
)
message.template_id = 'template-id'
message.dynamic_template_data = {
'name': user.name,
'order_id': user.order_id
}
sg.send(message)Q5:SMTP 的 Port 25、587、465 有什麼差異?
答案:
Port 對比:
| Port | 名稱 | 用途 | 加密方式 | 現代使用 |
|---|---|---|---|---|
| 25 | SMTP | 伺服器間轉發 | 無加密(或 STARTTLS) | ✅ 伺服器用 |
| 587 | Submission | 客戶端提交 | STARTTLS | ✅ 推薦 |
| 465 | SMTPS | 客戶端提交 | SSL/TLS | ✅ 也常用 |
詳細說明:
1. Port 25(傳統 SMTP)
用途:伺服器對伺服器(MTA to MTA)
加密:通常無加密(純文字)
smtp.alice.com:25 → smtp.bob.com:25
(郵件伺服器之間轉發)
現狀:
- ISP 通常封鎖 Port 25(防止垃圾郵件)
- 不適合客戶端使用
- 伺服器間仍在使用2. Port 587(Submission - 推薦)⭐
用途:客戶端提交郵件(MUA to MTA)
加密:STARTTLS(明文升級為加密)
流程:
1. 客戶端連線到 Port 587(明文)
2. 發送 STARTTLS 命令
3. 升級為 TLS 加密連線
4. 進行認證和發送
優點:
✅ RFC 6409 標準
✅ 強制認證(需登入)
✅ 現代推薦方式
✅ Gmail、Outlook 都支援
Python 範例:
server = smtplib.SMTP('smtp.gmail.com', 587)
server.starttls() # 升級為 TLS
server.login(user, password)3. Port 465(SMTPS)
用途:客戶端提交郵件(SSL/TLS)
加密:從一開始就是 SSL/TLS(Implicit TLS)
流程:
1. 客戶端連線到 Port 465
2. 立即建立 SSL/TLS 加密連線
3. 進行認證和發送
歷史:
- 1990 年代註冊為 SMTPS
- 後來被撤銷(改推 Port 587)
- 但實務上仍廣泛使用
優點:
✅ 從頭到尾都是加密(更安全)
✅ 無需 STARTTLS 升級
✅ 許多服務商仍支援
Python 範例:
server = smtplib.SMTP_SSL('smtp.gmail.com', 465)
server.login(user, password) # 已經是加密連線STARTTLS vs SSL/TLS:
STARTTLS(Port 587):
明文連線 → 發送 STARTTLS → 升級為加密
優點:
✅ 可協商加密方式
✅ 向下相容(如果不支援加密也能用)
缺點:
⚠️ 初始連線是明文(有被竊聽風險)
⚠️ 可能被中間人攻擊降級
SSL/TLS(Port 465):
直接建立加密連線
優點:
✅ 從頭到尾加密(更安全)
✅ 無法被降級攻擊
缺點:
❌ 不支援就無法連線實務建議:
✅ 客戶端發信:用 Port 587(STARTTLS)或 465(SSL)
- Gmail:兩者都支援
- 推薦 587(標準)
❌ 不要用 Port 25:
- ISP 通常封鎖
- 缺乏認證機制
- 容易被濫用
伺服器間轉發:仍使用 Port 25
- 但建議啟用 STARTTLS記憶技巧:
Port 25 = 伺服器專用(Server to Server)
Port 587 = 客戶端提交(STARTTLS,推薦)⭐
Port 465 = 客戶端提交(SSL,也常用)📝 總結
SMTP 協定核心要點:
基本概念:
- SMTP:Simple Mail Transfer Protocol(簡單郵件傳輸協定)
- 功能:專門負責「發送」郵件 📮
- 流程:客戶端 → 伺服器 → 收件方伺服器
Port 使用:
- Port 25:伺服器間轉發(MTA to MTA)
- Port 587:客戶端提交(STARTTLS,推薦)⭐
- Port 465:客戶端提交(SSL/TLS)
核心命令:
EHLO → MAIL FROM → RCPT TO → DATA → QUIT安全機制:
- TLS/SSL:加密傳輸(STARTTLS 或 SSL)
- SPF:驗證發送者 IP
- DKIM:數位簽章驗證
- DMARC:整合 SPF/DKIM 的政策
最佳實踐:
- ✅ 使用 Port 587(STARTTLS)或 465(SSL)
- ✅ 設定 SPF/DKIM/DMARC 記錄
- ✅ 避免垃圾郵件特徵
- ✅ 大量發送用專業服務(SendGrid、MailGun)
- ✅ 提供取消訂閱功能
記憶口訣:
SMTP = 只負責「寄」
Port 587 = 客戶端用(推薦)
SPF/DKIM/DMARC = 防偽造三寶🔗 延伸閱讀
- 上一篇:08-1. Telnet 協定
- 下一篇:09-2. POP3 協定
- 相關文章:09-3. IMAP 協定
- RFC 5321(SMTP):https://datatracker.ietf.org/doc/html/rfc5321
- RFC 6409(Message Submission):https://datatracker.ietf.org/doc/html/rfc6409
- RFC 7208(SPF):https://datatracker.ietf.org/doc/html/rfc7208
- RFC 6376(DKIM):https://datatracker.ietf.org/doc/html/rfc6376
- RFC 7489(DMARC):https://datatracker.ietf.org/doc/html/rfc7489