خانه / آموزش‌ها / آموزش جامع کتابخانه smtplib در پایتون (ارسال ایمیل)

آموزش جامع کتابخانه smtplib در پایتون (ارسال ایمیل)

🐍 HomeOfPython
|
📅 1404/10/16

سطح مقدماتی (Beginner Level)

کتابخانه smtplib یکی از ماژول‌های داخلی و استاندارد پایتون است که برای ارسال ایمیل از طریق پروتکل SMTP (Simple Mail Transfer Protocol) استفاده می‌شود. در این سطح، با مفاهیم پایه پروتکل، نحوه اتصال به سرور و ارسال ایمیل‌های متنی ساده آشنا می‌شویم.

برای کار با ایمیل‌ها، معمولاً به دو کتابخانه نیاز داریم:

  1. smtplib: برای برقراری ارتباط با سرور و ارسال ایمیل.
  2. email: برای ساختاربندی محتوای ایمیل (موضوع، متن، گیرنده).

۱. برقراری ارتباط با سرور SMTP

اولین قدم برای ارسال ایمیل، ایجاد یک نشست (Session) با سرور ایمیل (مانند Gmail، Outlook یا سرور اختصاصی) است. برای این کار نیاز به آدرس سرور (Host) و شماره پورت (Port) دارید.

  • Host: مثلاً smtp.gmail.com
  • Port: معمولاً 587 (برای TLS) یا 465 (برای SSL).

مثال اول: ساختار کلی اتصال (Static)

در این مثال، صرفاً نحوه تعریف شیء و اتصال را می‌بینیم. از آنجا که این کد برای اجرا نیاز به سرور واقعی دارد، به صورت استاتیک نمایش داده می‌شود.

python
import smtplib

# تعریف مشخصات سرور (مثال برای جیمیل)
smtp_server = "smtp.gmail.com"
port = 587  # پورت استاندارد برای TLS

# ایجاد شیء SMTP
try:
    server = smtplib.SMTP(smtp_server, port)
    server.ehlo() # معرفی کلاینت به سرور
    print("اتصال با موفقیت برقرار شد.")
    server.quit()
except Exception as e:
    print(f"خطا در اتصال: {e}")

مثال دوم: استفاده از with (مدیریت خودکار منابع)

بهترین روش برای مدیریت اتصال، استفاده از Context Manager است تا اتصال به صورت خودکار بسته شود.

python
import smtplib

def check_connection():
    # استفاده از with برای اطمینان از بسته شدن اتصال
    # توجه: این کد بدون دسترسی به اینترنت و سرور واقعی کار نمی‌کند
    try:
        with smtplib.SMTP("smtp.example.com", 587) as server:
            server.noop() # عملیات بدون اثر برای تست اتصال
            print("Server is responsive")
    except:
        print("Connection failed")

۲. آماده‌سازی و ارسال ایمیل متنی (Plain Text)

برای ارسال ایمیل، سرورهای مدرن نیاز به احراز هویت (Login) دارند. همچنین ساختار ایمیل باید استاندارد باشد. ما از ماژول email.mime برای ساخت بدنه ایمیل استفاده می‌کنیم.

نکته مهم: برای استفاده از سرویس‌هایی مثل Gmail، باید از "App Password" استفاده کنید، زیرا رمز عبور معمولی اکانت گوگل به دلایل امنیتی مستقیماً کار نمی‌کند.

مثال اول: ساختار ایمیل با MIMEText (Interactive)

در این مثال، نحوه ساخت یک شیء ایمیل را می‌بینیم. این بخش نیاز به سرور ندارد و صرفاً ساختار داده را نشان می‌دهد، بنابراین قابل اجراست.

Python

مثال دوم: کد کامل ارسال ایمیل (Static)

این قطعه کد، فرآیند کامل لاگین و ارسال را انجام می‌دهد.

python
import smtplib
from email.mime.text import MIMEText

sender = "user@gmail.com"
password = "YOUR_APP_PASSWORD" # رمز عبور اپلیکیشن
receiver = "target@example.com"

msg = MIMEText("متن ایمیل تستی", "plain", "utf-8")
msg["Subject"] = "تست ارسال"
msg["From"] = sender
msg["To"] = receiver

try:
    # اتصال با رمزنگاری TLS
    with smtplib.SMTP("smtp.gmail.com", 587) as server:
        server.starttls() # ارتقاء امنیت اتصال
        server.login(sender, password)
        server.sendmail(sender, receiver, msg.as_string())
        print("ایمیل با موفقیت ارسال شد!")
except Exception as e:
    print(f"Error: {e}")

سطح پیشرفته (Professional Level)

در پروژه‌های واقعی و سازمانی، ارسال ایمیل صرفاً فرستادن یک متن ساده نیست. شما نیاز به ارسال فایل‌های ضمیمه (Attachments)، طراحی قالب‌های HTML زیبا، مدیریت امنیت (SSL/TLS) و هندل کردن خطاهای شبکه دارید.

۱. ارسال ایمیل چندبخشی (Multipart) و HTML

پروتکل ایمیل اجازه می‌دهد محتواهای مختلفی (متن ساده، HTML، فایل) در یک بسته ارسال شوند. برای این کار از کلاس MIMEMultipart استفاده می‌کنیم. بسیار مهم است که هم نسخه plain و هم نسخه html را ارسال کنید تا اگر کلاینت گیرنده HTML را پشتیبانی نکرد، متن ساده را نمایش دهد.

ساختار MIMEMultipart

مثال اول: ساخت ایمیل HTML (Interactive)

این کد نحوه ترکیب متن ساده و HTML را نشان می‌دهد و خروجی ساختاریافته را چاپ می‌کند.

Python

۲. افزودن فایل ضمیمه (Attachments)

برای ارسال فایل (مثل PDF یا تصاویر)، باید فایل را به صورت باینری خوانده و سپس آن را encode (معمولاً base64) کنید تا در پروتکل متنی SMTP قابل انتقال باشد.

مثال فنی: تابع ارسال با ضمیمه (Static)

این تابع یک فایل را می‌خواند و به ایمیل ضمیمه می‌کند.

python
import smtplib
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
from email import encoders
import os

def send_email_with_attachment(filename, sender, password, receiver):
    msg = MIMEMultipart()
    msg["From"] = sender
    msg["To"] = receiver
    msg["Subject"] = "ارسال فایل گزارش"

    # باز کردن فایل و خواندن به صورت باینری
    with open(filename, "rb") as attachment:
        # ایجاد شیء MIMEBase
        part = MIMEBase("application", "octet-stream")
        part.set_payload(attachment.read())

    # انکود کردن فایل به base64
    encoders.encode_base64(part)

    # افزودن هدرهای لازم برای تشخیص فایل توسط گیرنده
    part.add_header(
        "Content-Disposition",
        f"attachment; filename= {os.path.basename(filename)}",
    )

    msg.attach(part)

    # اتصال و ارسال (بخش شبکه)
    with smtplib.SMTP_SSL("smtp.gmail.com", 465) as server:
        server.login(sender, password)
        server.send_message(msg)

۳. مدیریت خطاها و نکات امنیتی (SSL vs TLS)

تفاوت اصلی بین SMTP و SMTP_SSL در نحوه هندشیک (Handshake) اولیه است:

  • STARTTLS (Port 587): ابتدا اتصال ناامن برقرار می‌شود، سپس با دستور starttls() رمزگذاری می‌شود.
  • SSL (Port 465): اتصال از همان ابتدا رمزگذاری شده است (امن‌تر و توصیه‌شده برای اکثر سرورهای جدید).

مثال: هندلینگ حرفه‌ای خطاها (Static)

در سیستم‌های اتوماسیون، باید انواع خطاهای SMTP را جداگانه مدیریت کنید.

python
import smtplib

def safe_send_email():
    try:
        server = smtplib.SMTP("smtp.example.com", 587, timeout=10)
        server.starttls()
        server.login("user", "pass")
        server.sendmail("from", "to", "msg")
    
    except smtplib.SMTPAuthenticationError:
        print("خطا: نام کاربری یا رمز عبور اشتباه است.")
    
    except smtplib.SMTPConnectError:
        print("خطا: عدم توانایی در اتصال به سرور.")
        
    except smtplib.SMTPRecipientsRefused:
        print("خطا: آدرس گیرنده معتبر نیست یا رد شده است.")
        
    except smtplib.SMTPException as e:
        print(f"یک خطای کلی SMTP رخ داد: {e}")
        
    finally:
        try:
            server.quit()
        except:
            pass # اگر سرور قطع شده باشد، نیازی به quit نیست

۴. دیباگ کردن (Debugging)

زمانی که ایمیل ارسال نمی‌شود، بهترین راه فعال‌کردن حالت دیباگ smtplib است تا تمام رد و بدل‌های بین کلاینت و سرور را در کنسول ببینید.

Python