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-209-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加密方式
SMTP25587 (STARTTLS), 465 (SSL)TLS
POP3110995SSL
IMAP143993SSL

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/Flag

3. 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 Bye

Python 實作:

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名稱用途加密方式現代使用
25SMTP伺服器間轉發無加密(或 STARTTLS)✅ 伺服器用
587Submission客戶端提交STARTTLS推薦
465SMTPS客戶端提交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
0%