Python3郵件發送全指南:文本、HTML與附件

在 Python3 中,使用內置的 smtplib 庫和 email 模塊發送郵件是一個常見的需求。以下是更詳細的實現指南,包含各種場景的解決方案和技術細節:

一、發送純文本郵件的完整實現

  • 準備工作:
    • 確保已開通 SMTP 服務(各郵箱開啟方式不同)
    • 獲取 SMTP 授權碼(非登錄密碼)
    • 確認服務器地址和端口(常見配置見下表)
郵箱服務SMTP服務器SSL端口TLS端口
QQ郵箱smtp.qq.com465587
163郵箱smtp.163.com465994
Gmailsmtp.gmail.com465587
  • 核心代碼詳解:
import smtplib
import ssl
from email.mime.text import MIMEText
from email.header import Header
from email.utils import formataddr, formatdate, make_msgid
from datetime import datetime# 增強的郵件配置
config = {"smtp_server": "smtp.examples.com","smtp_port": 465,"sender_email": "your_email@example.com","sender_name": "系統管理員",  # 發件人顯示名稱"password": "your_smtp_password","receivers": [{"email": "user1@example.com", "name": "張經理"},{"email": "user2@example.com", "name": "李主管"}]
}# 構建郵件內容(支持多行模板)
email_template = """尊敬的{recipient_name}:這是來自{system_name}的系統通知郵件。當前時間:{current_time}
系統狀態:正常運行
最近事件:
{events}請及時處理相關事務。
"""events = "\n".join(["1. 用戶登錄異常(3次)","2. 數據庫備份完成","3. 新版本發布通知"
])# 填充模板內容
email_body = email_template.format(recipient_name="各位",  # 群發時的通用稱呼system_name="OA系統",current_time=datetime.now().strftime("%Y-%m-%d %H:%M:%S"),events=events
)# 創建MIME對象
msg = MIMEText(email_body, "plain", "utf-8")# 設置郵件頭(規范格式)
msg["From"] = formataddr((config["sender_name"], config["sender_email"]))
msg["To"] = ", ".join([formataddr((r["name"], r["email"])) for r in config["receivers"]]
)
msg["Subject"] = Header("【重要】系統狀態通知", "utf-8")# 高級郵件頭設置
msg["Date"] = formatdate(localtime=True)
msg["Message-ID"] = make_msgid()
msg["X-Priority"] = "1"  # 郵件優先級(1-5, 1最高)
msg["X-Mailer"] = "Python SMTP"  # 郵件客戶端標識# 安全發送流程
context = ssl.create_default_context()
try:with smtplib.SMTP_SSL(config["smtp_server"],config["smtp_port"],context=context,timeout=10  # 設置超時時間) as server:server.login(config["sender_email"], config["password"])# 實際發送時區分密送和抄送to_addresses = [r["email"] for r in config["receivers"]]server.sendmail(config["sender_email"],to_addresses,msg.as_string())print(f"成功發送郵件至 {len(to_addresses)} 位收件人")
except smtplib.SMTPException as e:print(f"郵件發送失敗,SMTP錯誤: {str(e)}")
except Exception as e:print(f"發生未知錯誤: {str(e)}")

二、HTML郵件的專業實現

  • 高級功能支持:
    • 響應式設計(適應移動端)
    • 嵌入式CSS和JavaScript
    • 動態內容渲染
    • 郵件跟蹤(通過嵌入圖片)
  • 完整示例:
from email.mime.multipart import MIMEMultipart# 創建多部分郵件
msg = MIMEMultipart("alternative")
msg["From"] = formataddr(("市場部", "marketing@company.com"))
msg["To"] = "customer@example.com"# 純文本備用內容
text_part = MIMEText("這是純文本備用內容", "plain", "utf-8")# HTML主要內容
html_content = """
<!DOCTYPE html>
<html>
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>產品推廣郵件</title><style type="text/css">/* 響應式設計 */body { font-family: 'Helvetica Neue', Arial, sans-serif; margin: 0; padding: 0; }.container { max-width: 600px; margin: 0 auto; padding: 20px; }.header { background-color: #3498db; color: white; padding: 20px; text-align: center; }.content { padding: 20px; line-height: 1.6; }.button { display: inline-block; background: #2ecc71; color: white; padding: 10px 20px; text-decoration: none; border-radius: 5px; }.footer { color: #7f8c8d; font-size: 12px; text-align: center; padding: 20px; }@media screen and (max-width: 480px) {.container { width: 100% !important; }}</style>
</head>
<body><div class="container"><div class="header"><h1>新產品發布</h1></div><div class="content"><p>尊敬的客戶:</p><p>我們很高興向您介紹我們的最新產品...</p><p><a href="https://example.com/product" class="button">立即查看</a></p><!-- 產品特性表格 --><table border="0" cellpadding="0" cellspacing="0" width="100%"><tr><td width="50%" valign="top"><h3>核心功能</h3><ul><li>高性能處理</li><li>簡單易用</li></ul></td><td width="50%" valign="top"><h3>技術優勢</h3><ul><li>先進算法</li><li>穩定可靠</li></ul></td></tr></table><!-- 郵件跟蹤像素 --><img src="https://example.com/track?email=customer@example.com" width="1" height="1"></div><div class="footer"><p>? 2023 公司名稱. 保留所有權利.</p><p><a href="%unsubscribe_url%">退訂郵件</a></p></div></div>
</body>
</html>
"""html_part = MIMEText(html_content, "html", "utf-8")# 添加郵件部分
msg.attach(text_part)  # 注意順序:先添加純文本版本
msg.attach(html_part)# 發送邏輯同上...

三、帶附件郵件的專業實現

郵件附件的處理是郵件系統開發中的關鍵環節,需要注意以下技術要點:

  • 自動檢測MIME類型

    • 通過文件擴展名識別(如.jpg對應image/jpeg)
    • 使用文件頭信息檢測(如PDF文件的%PDF標識)
    • 可集成第三方庫如Apache Tika進行精確識別
    • 示例:檢測到.txt文件自動設置Content-Type為text/plain
  • 支持大文件分塊處理

    • 采用BASE64編碼時注意76字符換行規則
    • 實施斷點續傳機制
    • 使用HTTP/1.1的chunked傳輸編碼
    • 典型場景:10MB以上的視頻文件傳輸
  • 處理中文文件名

    • 必須進行RFC 2231編碼(如=?UTF-8?B?5Lit5paH?=)
    • 文件名長度限制為75個字符
    • 避免使用非ASCII字符的擴展名
    • 示例處理流程:UTF-8編碼 → BASE64編碼 → MIME頭格式化
  • 添加多個附件

    • 每個附件作為獨立的MIME part
    • 使用multipart/mixed作為頂層Content-Type
    • 注意附件順序對郵件客戶端顯示的影響
    • 典型實現:附件1(合同.pdf)+附件2(報價單.xlsx)
  • 其他注意事項

    • 設置正確的Content-Disposition(attachment/inline)
    • 處理Windows/Linux路徑差異
    • 添加附件描述信息(Content-Description頭字段)
    • 安全考慮:病毒掃描和文件類型限制
  • 完整示例:
import os
import mimetypes
from email.mime.base import MIMEBase
from email import encodersdef add_attachment(msg, filepath):"""專業添加附件方法"""if not os.path.exists(filepath):raise FileNotFoundError(f"附件文件不存在: {filepath}")# 猜測MIME類型ctype, encoding = mimetypes.guess_type(filepath)if ctype is None or encoding is not None:ctype = "application/octet-stream"maintype, subtype = ctype.split("/", 1)with open(filepath, "rb") as fp:part = MIMEBase(maintype, subtype)part.set_payload(fp.read())# 編碼和設置頭信息encoders.encode_base64(part)# 處理中文文件名filename = os.path.basename(filepath)part.add_header("Content-Disposition","attachment",filename=Header(filename, "utf-8").encode())msg.attach(part)# 創建帶附件的郵件
msg = MIMEMultipart()
msg["Subject"] = "季度報告和數據分析"# 添加正文
msg.attach(MIMEText("請查收附件中的季度報告", "plain"))# 添加多個附件
attachments = ["/reports/Q3_Report.pdf","/data/sales_data.xlsx","/images/performance_chart.png"
]for attachment in attachments:try:add_attachment(msg, attachment)print(f"已添加附件: {os.path.basename(attachment)}")except Exception as e:print(f"添加附件失敗: {str(e)}")# 發送邏輯...

四、企業級最佳實踐

連接池管理增強版

from smtplib import SMTP_SSL
from queue import Queue
import threadingclass SMTPConnectionPool:def __init__(self, host, port, username, password, pool_size=5):self.host = hostself.port = portself.username = usernameself.password = passwordself.pool = Queue(pool_size)self.lock = threading.Lock()# 初始化連接池for _ in range(pool_size):conn = SMTP_SSL(host, port)conn.login(username, password)self.pool.put(conn)def get_connection(self):return self.pool.get()def release_connection(self, conn):self.pool.put(conn)def send_email(self, msg, recipients):conn = Nonetry:conn = self.get_connection()conn.sendmail(self.username, recipients, msg.as_string())finally:if conn:self.release_connection(conn)# 使用示例
pool = SMTPConnectionPool(host="smtp.example.com",port=465,username="user@example.com",password="password",pool_size=10
)# 在多線程環境中使用
def worker(email_list):for email in email_list:msg = build_email_message(email)pool.send_email(msg, [email["address"]])threads = []
for i in range(5):t = threading.Thread(target=worker, args=(email_chunks[i],))threads.append(t)t.start()for t in threads:t.join()

完整的郵件服務類

import logging
from logging.handlers import RotatingFileHandlerclass EmailService:def __init__(self, config):self.config = configself.logger = self._setup_logger()self.connection_pool = self._init_connection_pool()def _setup_logger(self):logger = logging.getLogger("EmailService")logger.setLevel(logging.INFO)handler = RotatingFileHandler("email_service.log",maxBytes=10*1024*1024,  # 10MBbackupCount=5)formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")handler.setFormatter(formatter)logger.addHandler(handler)return loggerdef _init_connection_pool(self):return SMTPConnectionPool(host=self.config["smtp_host"],port=self.config["smtp_port"],username=self.config["smtp_user"],password=self.config["smtp_password"],pool_size=self.config.get("pool_size", 5))def send_email(self, template_name, recipient, context, attachments=None):"""發送模板郵件"""try:# 1. 加載模板template = self._load_template(template_name)# 2. 構建郵件內容msg = self._build_message(template, recipient, context)# 3. 添加附件if attachments:for attachment in attachments:self._add_attachment(msg, attachment)# 4. 發送郵件self.connection_pool.send_email(msg,[recipient["email"]])self.logger.info(f"郵件發送成功: {template_name} -> {recipient['email']}")return Trueexcept Exception as e:self.logger.error(f"郵件發送失敗: {template_name} -> {recipient['email']}: {str(e)}",exc_info=True)return False# 其他輔助方法...def _load_template(self, name):"""加載郵件模板"""passdef _build_message(self, template, recipient, context):"""構建郵件消息"""passdef _add_attachment(self, msg, filepath):"""添加附件"""pass

監控與統計集成

from prometheus_client import CollectorRegistry, push_to_gateway
from datetime import datetimeclass EmailMetrics:def __init__(self):self.registry = CollectorRegistry()self.emails_sent = Counter("emails_sent_total","Total emails sent",["template"],registry=self.registry)self.send_time = Summary("email_send_time_seconds","Time spent sending emails",registry=self.registry)self.errors = Counter("email_errors_total","Total email sending errors",["type"],registry=self.registry)def record_success(self, template, duration):self.emails_sent.labels(template).inc()self.send_time.observe(duration)def record_error(self, error_type):self.errors.labels(error_type).inc()def push_metrics(self):push_to_gateway("metrics.example.com:9091",job="email_service",registry=self.registry)# 使用示例
metrics = EmailMetrics()@metrics.send_time.time()
def send_email_with_metrics(email):try:start_time = datetime.now()# 發送郵件邏輯...duration = (datetime.now() - start_time).total_seconds()metrics.record_success(email["template"], duration)return Trueexcept smtplib.SMTPException as e:metrics.record_error("smtp")raiseexcept Exception as e:metrics.record_error("other")raisefinally:metrics.push_metrics()

五、高級主題擴展

DKIM簽名支持

import dkimdef add_dkim_signature(msg, domain, selector, private_key):"""添加DKIM簽名"""headers = ["From", "To", "Subject"]sig = dkim.sign(message=msg.as_bytes(),selector=selector.encode(),domain=domain.encode(),privkey=private_key.encode(),include_headers=headers)msg["DKIM-Signature"] = sig[len("DKIM-Signature: "):].decode()return msg# 使用示例
private_key = """-----BEGIN RSA PRIVATE KEY-----
...
-----END RSA PRIVATE KEY-----"""msg = add_dkim_signature(msg,domain="example.com",selector="selector1",private_key=private_key
)

郵件隊列系統集成

import redis
import json
import pickleclass EmailQueue:def __init__(self, redis_host="localhost", redis_port=6379):self.redis = redis.Redis(host=redis_host,port=redis_port,db=0,decode_responses=False)self.queue_name = "email_queue"def enqueue(self, email_task):"""將郵件任務加入隊列"""serialized = pickle.dumps(email_task)self.redis.rpush(self.queue_name, serialized)def dequeue(self):"""從隊列取出郵件任務"""serialized = self.redis.lpop(self.queue_name)if serialized:return pickle.loads(serialized)return Nonedef process_queue(self, worker_count=4):"""處理隊列中的郵件"""def worker():while True:task = self.dequeue()if not task:breaktry:send_email(**task)except Exception as e:self._handle_failure(task, e)threads = []for _ in range(worker_count):t = threading.Thread(target=worker)threads.append(t)t.start()for t in threads:t.join()# 使用示例
queue = EmailQueue()# 生產者添加任務
queue.enqueue({"to": "user@example.com","subject": "測試郵件","body": "這是一封測試郵件","template": "welcome"
})# 消費者處理隊列
queue.process_queue()

通過這些擴展實現,可以構建出適應不同場景的完整郵件解決方案,從簡單的通知郵件到復雜的企業級郵件服務。關鍵是根據實際需求選擇合適的技術方案,并注意處理各種邊界情況和異常狀態。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/913982.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/913982.shtml
英文地址,請注明出處:http://en.pswp.cn/news/913982.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

CSS和CSS3區別對比

CSS&#xff08;層疊樣式表&#xff09;與CSS3&#xff08;CSS的第三個版本&#xff09;的區別主要體現在功能擴展、語法特性以及應用場景等方面。以下是兩者的核心對比&#xff1a; 一、核心概念與版本關系CSS&#xff1a;是基礎樣式表語言&#xff0c;用于分離網頁內容與樣式…

JVM--監控和故障處理工具

一、命令行工具 1. jps (Java Process Status) 作用&#xff1a;列出當前系統中所有的 Java 進程 常用命令&#xff1a; jps -l # 顯示進程ID和主類全名 jps -v # 顯示JVM啟動參數 輸出示例&#xff1a; 1234 com.example.MainApp 5678 org.apache.catalina.startup.Bootstra…

推薦 7 個本周 yyds 的 GitHub 項目。

01.開源的 CRM 軟件這是一個開源的客戶關系管理&#xff08;CRM&#xff09;系統&#xff0c;現在又 32.5K 的 Star。為企業和團隊提供比肩 Salesforce 等商業產品的功能&#xff0c;同時強調用戶自主權、數據自由與高度可定制性。開源地址&#xff1a;https://github.com/twen…

linux網絡編程之單reactor模型(一)

Reactor 是一種事件驅動的設計模式&#xff08;Event-Driven Pattern&#xff09;&#xff0c;主要用于處理高并發 I/O&#xff0c;特別適合網絡服務器場景。它通過一個多路復用機制監聽多個事件源&#xff08;如 socket 文件描述符&#xff09;&#xff0c;并在事件就緒時將事…

瀏覽器重繪與重排

深入解析瀏覽器渲染&#xff1a;重排(Reflow)與重繪(Repaint)的性能陷阱與優化策略作為一名前端開發者&#xff0c;你是否遇到過界面突然卡頓、滾動時頁面抖動或輸入框響應遲鈍&#xff1f;這些常見性能問題背后&#xff0c;往往是重排與重繪在作祟。本文將深入剖析瀏覽器渲染機…

day049-初識Ansible與常用模塊

文章目錄0. 老男孩思想-人脈的本質1. Ansible1.1 密鑰認證1.2 安裝ansible1.3 添加ansible配置文件1.4 配置主機清單文件&#xff08;Inventory&#xff09;1.5 測試1.6 ansible的模塊思想1.7 command模塊1.8 需求&#xff1a;每臺服務器的密碼都不同&#xff0c;怎么批量執行業…

力扣網編程134題:加油站(雙指針)

一. 簡介 前面兩篇文章使用暴力解法&#xff0c;或者貪心算法解決了力扣網的加油站問題&#xff0c;文章如下&#xff1a; 力扣網編程150題&#xff1a;加油站&#xff08;暴力解法&#xff09;-CSDN博客 力扣網編程150題&#xff1a;加油站&#xff08;貪心解法&#xff09…

XPath 語法【Web 自動化-定位方法】

&#x1f9ed; XPath 語法簡介&#xff08;Web 自動化核心定位手段&#xff09;一、XPath 是什么&#xff1f;XPath&#xff08;XML Path Language&#xff09;是用于在 XML/HTML 文檔中定位節點的語言&#xff0c;由 W3C 標準定義。瀏覽器支持的是 XPath 1.0。應用場景廣泛&am…

記一次 Linux 安裝 docker-compose

一.下載 1.手動下載 下載地址&#xff1a;https://github.com/docker/compose/releases 下載后&#xff0c;放在/usr/local/bin/目錄下&#xff0c;命名為&#xff1a;docker-compose 2.命令下載 sudo curl -L "https://github.com/docker/compose/releases/download/…

Go語言WebSocket編程:從零打造實時通信利器

1. WebSocket的魅力&#xff1a;為什么它這么火&#xff1f;WebSocket&#xff0c;簡單來說&#xff0c;就是一種在單條TCP連接上實現全雙工通信的神器。相比HTTP的請求-響應模式&#xff0c;它像是一條隨時暢通的電話線&#xff0c;客戶端和服務器可以隨時“喊話”&#xff0c…

速學 RocketMQ

目錄 本地啟動&測試&可視化 核心概念 集群 主從 集群 Dledger 集群 總結 客戶端消息確認機制 廣播模式 消息過濾機制 順序消息機制 延遲消息與批量消息 事務消息機制 ACL權限控制體系 RocketMQ客戶端注意事項 消息的 ID、Key、Tag 最佳實踐 消費者端…

【個人思考】不點菜的美學:Omakase 的信任、四季與食藝

本文原創作者:姚瑞南 AI-agent 大模型運營專家/音樂人/野生穿搭model,先后任職于美團、獵聘等中大廠AI訓練專家和智能運營專家崗;多年人工智能行業智能產品運營及大模型落地經驗,擁有AI外呼方向國家專利與PMP項目管理證書。(轉載需經授權) 目錄 ?? 什么是 Omakase?…

vivo Pulsar 萬億級消息處理實踐(3)-KoP指標異常修復

作者&#xff1a;vivo 互聯網大數據團隊- Chen Jianbo 本文是《vivo Pulsar萬億級消息處理實踐》系列文章第3篇。 Pulsar是Apache基金會的開源分布式流處理平臺和消息中間件&#xff0c;它實現了Kafka的協議&#xff0c;可以讓使用Kafka API的應用直接遷移至Pulsar&#xff0c;…

Marin說PCB之Allegro高亮BOM器件技巧詳解

一&#xff0c;首先在原理圖輸出BOM的時候&#xff0c;只需要勾選器件的位號這個選項即可&#xff0c;具體操作如下所示&#xff1a;二&#xff0c;輸出BOM完成后&#xff0c;打開表格選擇我們器件的位號那列即可&#xff0c;然后復制到我們的TEXT文本中。三&#xff0c;接著就…

數據結構與算法——從遞歸入手一維動態規劃【2】

前言&#xff1a; 記錄一下對左程云系列算法課程--算法講解066【必備】的剩余習題的學習。本文主要簡單記錄個人學習心得和提供C版本代碼。如需要題目的細致講解&#xff0c;請前往原視頻。 涉及內容&#xff1a; 動態規劃、三指針、 參考視頻&#xff1a; 左程云--算法講…

【理念●體系】Windows AI 開發環境搭建實錄:六層架構的逐步實現與路徑治理指南

【理念●體系】從零打造 Windows WSL Docker Anaconda PyCharm 的 AI 全鏈路開發體系-CSDN博客 Windows AI 開發環境搭建實錄&#xff1a;六層架構的逐步實現與路徑治理指南 ——理念落地篇&#xff0c;從路徑規劃到系統治理&#xff0c;打造結構化可復現的 AI 開發環境 AI…

5G標準學習筆記15 --CSI-RS測量

5G標準學習筆記15 --CSI-RS測量 前言 前面講了&#xff0c;在5GNR中&#xff0c;CSI-RS 是支持信道狀態評估、波束管理和無線資源管理&#xff08;RRM&#xff09;的關鍵參考信號。下面孬孬基于3GPP TS 38.331中的內容&#xff0c;詳細定義了基于 CSI-RS 的測量程序&#xff0c…

第P28:阿爾茨海默病診斷(優化特征選擇版)

&#x1f368; 本文為&#x1f517;365天深度學習訓練營 中的學習記錄博客&#x1f356; 原作者&#xff1a;K同學啊 一、進階說明 針對于特征對模型結果的影響我們做了特征分析 特征選擇 1. SelectFromModel 工作原理&#xff1a;基于模型的特征選擇方法&#xff0c;使用…

AI的歐幾里得要素時刻:從語言模型到可計算思維

引言 人工智能正在經歷一個關鍵的轉折點。就像歐幾里得的《幾何原本》為數學奠定了公理化基礎一樣&#xff0c;AI也正在尋找自己的"要素時刻"——一個能夠將當前的語言模型能力轉化為真正可計算、可驗證思考的轉變。 最近發表的論文《AI’s Euclid’s Elements Momen…

番外-linux系統運行.net framework 4.0的項目

基礎環境&#xff1a;linux系統&#xff0c;.net framework 4.0&#xff0c;npgsql 2.2.5.0 &#xff08;版本不同&#xff0c;構建可能失敗&#xff09; 方法背景&#xff1a;linux不支持運行.net framework 4.0&#xff0c;高版本mono不支持npgsql 2.x 主要使用&#xff1a…