Python Notes
Complete guide to email automation with Python using smtplib, email library, sending HTML emails, attachments, reading emails with IMAP, and scheduling email automation.
Introduction
You can automatically send and read emails using Python. smtplib (sending) and imaplib (reading) are part of the Standard Library — no extra installation required!
2. Simple Text Email
3. HTML Email
4. Email with Attachments
📝 Hindi Explanation
MIMEBase is for generic file attachments. encoders.encode_base64() converts binary data to email-safe base64 format. BCC (Blind Carbon Copy) should not be placed in the header — only add it to the recipients list. Otherwise, other recipients will see the BCC addresses.5. Reading Emails with IMAP
6. Email Filtering and Search
7. Email Automation Examples
8. Best Practices
Summary
| Library | Purpose |
|---|---|
smtplib | Send emails via SMTP |
imaplib | Read emails via IMAP |
MIMEText | Plain text / HTML content |
MIMEMultipart | Email with multiple parts |
MIMEBase | File attachments |
MIMEImage | Image attachments |
email.header | Decode email headers |
Pro Tip: For production email automation, consider using dedicated services like SendGrid, Mailgun, or AWS SES — they offer better deliverability, analytics, and don't have Gmail's daily sending limits.
📤 Output Examples
SMTP Connection Output
# From Section 1 - create_smtp_connection()
server = create_smtp_connection("your@gmail.com", "app_password", "gmail")Connected to smtp.gmail.com:587
Text Email Output
# From Section 2 - send_text_email()
send_text_email(SENDER, PASSWORD, "recipient@example.com", "Python Test", "Hello!")Email sent to recipient@example.com
Multiple Recipients Output
Email sent to 2 recipients
HTML Template Output
# From Section 3 - create_report_email()
html, plain = create_report_email("Alice Johnson", 95.5, "A", "Python Master Course")
print("HTML email template created!")
print(f"Template length: {len(html)} chars")HTML email template created! Template length: 1847 chars
Attachment Email Output
Attached: report.pdf Attached: data.csv Email with 2 attachments sent!
IMAP Read Emails Output
IMAP connected! From: WoHoTech <admin@wohotech.com> Subject: Python Course Update - June 2026 --- From: GitHub <noreply@github.com> Subject: [python-project] New pull request #42 --- From: Alice <alice@example.com> Subject: Re: Project Meeting Notes ---
Email Filter Output
# From Section 6 - filter_emails_by_sender()
ids = filter_emails_by_sender("your@gmail.com", "app_password", "admin@wohotech.com")Found 15 emails from admin@wohotech.com
Bulk Email Output
# From Section 7 - send_bulk_emails()
automation.send_bulk_emails(students, "Python Course Update — {name}", template)✓ Sent to alice@example.com ✓ Sent to bob@example.com 2/2 emails sent!
Email Validation Output
# From Section 8 - is_valid_email()
print(is_valid_email("alice@gmail.com"))
print(is_valid_email("not-an-email"))True False
⚠️ Common Mistakes
❌ Mistake 1: Hardcoding Credentials in Code
# ❌ WRONG — Never do this!
password = "my_secret_password123"
# ✅ CORRECT — Environment variables use karo
import os
password = os.getenv("EMAIL_APP_PASSWORD")Explanation: Hardcoding passwords directly in code is a security risk. If the code is pushed to GitHub, your account can be compromised. Always use environment variables or secret managers.
❌ Mistake 2: Using Gmail's Real Password
# ❌ WRONG — Gmail ka actual password
server.login("you@gmail.com", "gmail_ka_password")
# ✅ CORRECT — App Password use karo (16-character generated password)
server.login("you@gmail.com", "abcd efgh ijkl mnop")Explanation: Gmail rejects normal passwords when 2FA is enabled. Generate one from Google Account → Security → App Passwords. This 16-character password is specifically for third-party apps.
❌ Mistake 3: Putting BCC in the Header
Explanation: The purpose of BCC is to hide recipients from each other. If you add it to the header, the purpose is defeated — everyone will see the BCC addresses.
❌ Mistake 4: Connection Close Na Karna
# ❌ WRONG — Connection open reh jayegi
server = smtplib.SMTP("smtp.gmail.com", 587)
server.starttls()
server.login(email, password)
server.send_message(msg)
# server.quit() bhool gaye!
# ✅ CORRECT — Context manager use karo
with smtplib.SMTP("smtp.gmail.com", 587) as server:
server.starttls()
server.login(email, password)
server.send_message(msg)
# Automatically close hoga!Explanation: Using the with statement (context manager) is best practice. It ensures the connection is properly closed — even if an error occurs. Without it, connections can remain open and cause resource leaks.❌ Mistake 5: Error Handling Skip Karna
# ❌ WRONG — Koi error handling nahi
server.send_message(msg)
# ✅ CORRECT — Proper try/except
try:
server.send_message(msg)
print("Email sent successfully!")
except smtplib.SMTPRecipientsRefused as e:
print(f"Invalid recipient: {e}")
except smtplib.SMTPException as e:
print(f"SMTP error: {e}")Explanation: Errors are common in network operations — invalid address, server down, rate limit exceeded. Without error handling, your program will crash on the first failure. Always use try/except with specific exception types.
❌ Mistake 6: Ignoring Rate Limiting in Bulk Emails
# ❌ WRONG — Gmail daily limit exceed ho jayegi
for user in 10000_users:
send_email(user) # Gmail limit: ~500/day (free accounts)
# ✅ CORRECT — Be mindful of delays and limits
import time
for i, user in enumerate(users):
if i > 0 and i % 50 == 0:
time.sleep(60) # Wait 1 minute after 50 emails
send_email(user)Explanation: Gmail free accounts have a ~500 emails/day limit and Google Workspace has ~2000/day. Exceeding the limit can temporarily block your account (24 hours). Always add delays between batches.
❌ Mistake 7: Email Body mein Plain Text Fallback Na Dena
# ❌ WRONG — Only HTML, no fallback
msg = MIMEMultipart("alternative")
msg.attach(MIMEText(html_content, "html"))
# ✅ CORRECT — Plain text + HTML dono add karo
msg = MIMEMultipart("alternative")
msg.attach(MIMEText(plain_text, "plain")) # Pehle plain text
msg.attach(MIMEText(html_content, "html")) # Phir HTML (preferred)Explanation: Some email clients (especially older ones or text-only mode) don't render HTML. Providing a plain text fallback ensures your message is always readable.
✅ Key Takeaways
- 📧 smtplib is for sending emails (SMTP protocol), imaplib is for reading emails (IMAP protocol) — both are built into the Python Standard Library
- 🔐 Always use App Password (16-character) with Gmail — normal passwords won't work on 2FA-enabled accounts
- 🔒 TLS/SSL encryption is mandatory — use
STARTTLS(port 587) orSMTP_SSL(port 465), never a plain text connection - 📎 MIME classes define email structure —
MIMEMultipart(container),MIMEText(text/html),MIMEBase(attachments),MIMEImage(images) - 📝 Always include a plain text fallback in HTML emails — use
MIMEMultipart("alternative")and attach plain text first - 👁️ Never put BCC in the email header — only add it to the
sendmail()recipients list, otherwise it becomes visible to all - 🔄 Use a context manager (
withstatement) for SMTP connections — ensures automatic cleanup even if an error occurs - ⏱️ Pay attention to rate limiting in bulk emails — Gmail: ~500/day (free), ~2000/day (Workspace). Add delays between batches
- 🌍 For production email automation, consider SendGrid, Mailgun, or AWS SES — better deliverability, analytics, and higher limits
- 🛡️ Always store credentials in environment variables or secret managers — hardcoding in code is the biggest security anti-pattern
❓ FAQ
Q1: Why isn't my Python script sending email via Gmail? Getting "Authentication failed" error?
Answer: Gmail doesn't accept normal passwords for third-party apps when 2FA (2-Step Verification) is enabled. You need to generate an App Password: Google Account → Security → 2-Step Verification → App Passwords.
Q2: What is the difference between smtplib.SMTP and smtplib.SMTP_SSL?
Answer: SMTP("smtp.gmail.com", 587) first creates a plain connection then encrypts it by calling starttls() (STARTTLS upgrade). SMTP_SSL("smtp.gmail.com", 465) starts with an encrypted connection from the beginning. Both are secure; use port 587 for STARTTLS or port 465 for direct SSL.
Q3: How many emails can you send at once via Gmail?
Answer: Gmail free account: ~500 emails/day. Google Workspace: ~2000 emails/day. If you exceed the limit, your account may be temporarily blocked (24 hours). For high-volume sending, use services like SendGrid or AWS SES.
Q4: How do you add inline images in an email (displayed in the body, not as attachments)?
Answer: Use MIMEImage with a Content-ID header, then reference it with cid: in the HTML:
from email.mime.image import MIMEImage
# Image attach karo with Content-ID
with open("logo.png", "rb") as f:
img = MIMEImage(f.read())
img.add_header("Content-ID", "<logo>")
img.add_header("Content-Disposition", "inline")
message.attach(img)
# Reference in HTML
html = '<img src="cid:logo" alt="Logo">'This technique is widely used in email signatures and newsletters! 🖼️
Q5: Getting encoding errors when reading emails via IMAP — how to fix?
Answer: Emails can have multiple encodings (UTF-8, ISO-8859-1, etc.). Always use errors="replace" or errors="ignore" when decoding:
# Safe decoding
body = payload.decode(encoding or "utf-8", errors="replace")
subject = subject.decode(encoding or "utf-8", errors="replace")The decode_header() function provides encoding info — check first whether it's bytes or already a string. Use defensive coding to avoid Unicode errors.
Q6: Can you send Outlook/Yahoo emails using Python?
Answer: Yes! Just change the SMTP server and port:
- Outlook:
smtp.office365.com, port 587 (STARTTLS) - Yahoo:
smtp.mail.yahoo.com, port 587 (STARTTLS) - iCloud:
smtp.mail.me.com, port 587 (STARTTLS)
The code remains almost the same — only the host/port configuration changes. You may need to generate an app-specific password for each provider. 📬
Q7: How do you schedule an email automation script (daily/weekly automatic)?
Answer: Multiple options hain:
schedulelibrary (Python): Simple in-process schedulingcron(Linux/Mac):0 9 * * * python3 /path/to/email_script.py(daily 9 AM)- Task Scheduler (Windows): GUI based scheduling
- Cloud: AWS Lambda + CloudWatch Events, GitHub Actions (cron syntax)
Cloud-based solutions are better for production since they continue running even when the local machine is off. ⏰
Q8: How do you confirm email delivery after sending?
Answer: The SMTP protocol doesn't provide guaranteed delivery confirmation. Options include:
- Read receipts:
message["Disposition-Notification-To"] = sender(recipient decline kar sakta hai) - Delivery Status Notification:
message["Return-Receipt-To"] = sender - SendGrid/Mailgun webhooks: Track events (delivered, opened, clicked)
- Tracking pixel: Embed a tiny image in the HTML email that hits your server
For production, third-party services (SendGrid, Mailgun) are the best option for delivery tracking. 📩
🎯 Interview Questions
Q1: Which libraries are used for sending emails in Python? Explain the role of SMTP and MIME.
Answer: For sending emails in Python, primarily smtplib (SMTP connection and sending) and the email package (message construction) are used. SMTP handles the connection and delivery protocol. MIME (Multipurpose Internet Mail Extensions) defines the email structure — headers, text, HTML, attachments.
Q2: What is the difference between MIMEMultipart("alternative") and MIMEMultipart("mixed")?
Answer: "alternative" subtype means different representations of the same content (plain text + HTML) — the email client chooses the best format. "mixed" subtype means different types of content together (text + attachments) — all parts are displayed/downloaded.
Q3: What is the difference between TLS and SSL in the email context? Explain Port 587 vs 465.
Answer: Port 587 (STARTTLS): First a plain text connection is established, then the STARTTLS command upgrades it to an encrypted connection. Port 465 (Implicit SSL): The connection is encrypted from the start. Modern recommendation: use port 587 with STARTTLS.
Q4: How would you handle rate limiting in bulk email automation? Describe a production-ready approach.
Answer: A production-ready approach requires multiple layers:
- Delay between sends:
time.sleep(1-2)per email ya batch delays - Queue system: Push emails to a Redis/RabbitMQ queue, let worker processes handle sending
- Exponential backoff: Double the wait time on rate limit errors (2s → 4s → 8s)
- Track daily limits: Maintain a counter, pause when nearing the limit
- Dedicated service: Use SendGrid/AWS SES which provide built-in rate management
- Connection reuse: Don't create a new connection per email — send multiple emails over one connection
- Error categorization: Handle permanent failures (invalid email) vs temporary ones (server busy) differently
Q5: What is the common security mistake in BCC implementation? Describe the correct approach.
Answer: Common mistake: Putting BCC addresses in the message["Bcc"] header. This is a security vulnerability because some mail servers forward headers as-is, exposing BCC addresses. Correct approach: Only add BCC addresses to the sendmail() recipients list, never to the message header.
Q6: What is the difference between IMAP and POP3? Which is better for email reading?
Answer: IMAP (Internet Message Access Protocol): Emails stay on the server, sync across multiple devices, supports folders, and allows selective download. POP3 (Post Office Protocol): Downloads emails and typically deletes from server, single device, no folder sync. IMAP is better for modern multi-device usage.
Q7: What should the error handling strategy be in email automation? Explain different exceptions.
Answer: Key exceptions aur handling:
SMTPAuthenticationError: Wrong credentials → Notify the user, check App PasswordSMTPRecipientsRefused: Invalid recipient → Log it, skip it, don't retrySMTPSenderRefused: Sender blocked → Account status check karoSMTPConnectError: Server unreachable → Retry with backoffSMTPServerDisconnected: Connection dropped mid-send → Reconnect karoSMTPDataError: Message rejected (too large, etc.) → Message fix karosocket.timeout: Network slow → Timeout increase karo ya retry
Best practice: Catch specific exceptions first, generic SMTPException last. Put failed emails in a separate queue for retry. Log permanent failures and alert.
Q8: What are the CSS limitations in email HTML? What are the best practices for email template design?
Answer: Email HTML is very different from web HTML:
- No external CSS:
<link>tags don't work — use inline styles - No JavaScript: Script execution blocked hai
- Limited CSS:
float,position,flexbox,gridunreliable hain - Tables for layout:
<table>based layout most compatible hai - Inline styles only: Some clients remove
<style>blocks (especially Gmail) - Images blocked by default: Alt text important hai
- Max width ~600px: For mobile compatibility
Best practices: Use tables for layout, apply inline CSS, provide alt text for images, include a plain text fallback, and test across multiple email clients.
Q9: What is the maximum attachment size for emails in Python? How do you handle large files?
Answer: Technical limits:
- Gmail: 25 MB per email (attachments included)
- Outlook: 20 MB default
- SMTP servers: Generally 10-25 MB
- Base64 encoding: File size increases ~33% after encoding
For large files, use alternatives:
- Share a cloud link: Include Google Drive/S3 link in email
- File compression: ZIP karo before attaching
- Split attachments: Divide across multiple emails
- Dedicated file transfer: WeTransfer/Dropbox type service use karo
Check file size in code before sending: if os.path.getsize(file) > 20_000_000: use_cloud_link()
Q10: Gmail API vs smtplib — when should you use which? Describe pros/cons.
Answer: smtplib (SMTP):
- ✅ Simple, no setup, Standard Library
- ✅ Works with any email provider
- ❌ Limited features (no labels, no thread management)
- ❌ Rate limits strict, no delivery tracking
- 🎯 Best for: Simple scripts, quick automation, learning
Gmail API (OAuth2):
- ✅ Full Gmail features (labels, threads, search, drafts)
- ✅ Better rate limits, OAuth2 security
- ✅ Read receipts, delivery tracking possible
- ❌ Complex setup (Google Cloud Console, OAuth consent)
- ❌ Gmail-specific (not portable to other providers)
- 🎯 Best for: Production apps, Gmail-specific features needed
Rule of thumb: Prototype/learning → smtplib. Production Gmail app → Gmail API. Multi-provider production → SendGrid/AWS SES.
Exam Focus
Revise definitions, diagrams, examples, and short-answer points for Email Automation with Python.
Interview Use
Prepare one clear explanation, one practical example, and one common mistake for this Python Master Course topic.
Search Terms
python-master-course, python master course, python, master, course, automation, email, email automation with python
Related Python Master Course Topics