
Sending emails programmatically is a powerful functionality that can greatly enhance automation, productivity, and communication in various software solutions. Python is a versatile programming language that provides straightforward tools to accomplish this. Thanks to its built-in libraries and support for external modules, Python allows developers to send emails with body content and attachments using the Simple Mail Transfer Protocol (SMTP). This article will walk you through the process of sending emails with attachments using Python in a reliable, secure, and efficient way.
Why Use Python for Sending Emails?
Python excels in scripting and data manipulation tasks, making it well-suited for automating operations such as report generation, log transmissions, and alerts via email. Using Python ensures versatility, ease of maintenance, and compatibility with a wide range of email services including Gmail, Outlook, and custom SMTP servers.
Key Concepts to Understand
Before diving into code, it’s important to understand some foundational concepts:
- SMTP: The protocol used to transfer email messages between mail servers and clients.
- MIME: Multipurpose Internet Mail Extensions allow sending not only text but also multimedia files as email content and attachments.
- Authentication: To prevent unauthorized access, mail servers require login credentials when sending emails via SMTP.
Essential Libraries
To send emails with attachments in Python, you will typically need the following libraries:
- smtplib: A built-in Python module used for sending emails via SMTP.
- email.mime: Used to construct email messages with various parts such as headers, plain text, HTML, or attachments.
Step-by-Step Guide to Sending Emails with Attachments
1. Import Required Modules
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
2. Setup Email Parameters
You need to define key pieces of information such as the sender, recipient, subject, body, and file path for the attachment.
sender_email = "your_email@example.com"
recipient_email = "recipient@example.com"
subject = "Monthly Report"
body = "Please find the attached report for this month."
# File to attach
filename = "report.pdf"
3. Compose the Email
# Create message container
message = MIMEMultipart()
message['From'] = sender_email
message['To'] = recipient_email
message['Subject'] = subject
# Attach the email body
message.attach(MIMEText(body, 'plain'))
4. Attach a File
# Open the file in binary mode
with open(filename, "rb") as attachment:
part = MIMEBase("application", "octet-stream")
part.set_payload(attachment.read())
# Encode file in ASCII characters
encoders.encode_base64(part)
# Add header
part.add_header(
"Content-Disposition",
f"attachment; filename= {filename}",
)
# Attach the part to message
message.attach(part)
5. Connect to SMTP Server and Send Email
Based on the email provider (e.g., Gmail, Outlook), the SMTP server settings will vary. Here’s an example using Gmail:
# SMTP server configuration
smtp_server = "smtp.gmail.com"
smtp_port = 587
smtp_user = "your_email@example.com"
smtp_password = "your_password"
# Create secure connection with server and send email
with smtplib.SMTP(smtp_server, smtp_port) as server:
server.starttls() # Upgrade the connection to secure
server.login(smtp_user, smtp_password)
server.sendmail(sender_email, recipient_email, message.as_string())
Best Practices for Secure Emailing
Security is critical when handling email accounts and recipient data. Below are some important tips to follow:
- Use environment variables or encrypted configuration files instead of hardcoding credentials.
- Use application-specific passwords when using services like Gmail or Outlook.
- Implement email validation to avoid invalid recipients or improper inputs.
- Apply error handling mechanisms to capture and react to issues such as invalid logins or unreachable SMTP servers.
Handling Multiple Attachments
To attach multiple files, simply loop over a list of file paths and repeat the attachment process for each:
attachments = ["report.pdf", "summary.xlsx", "chart.png"]
for file in attachments:
with open(file, "rb") as f:
part = MIMEBase("application", "octet-stream")
part.set_payload(f.read())
encoders.encode_base64(part)
part.add_header("Content-Disposition", f"attachment; filename= {file}")
message.attach(part)
Working with HTML Email Bodies
If you want richer formatting in your emails, replace the plain text body with an HTML version:
html = """\
Dear Team,
Please find the monthly reports attached.
Regards,
The Automation System
"""
message.attach(MIMEText(html, "html"))
This is particularly useful for newsletters, alerts, or branded messages.

Common Problems and Troubleshooting
Sometimes, sending email via SMTP doesn’t work as expected. Here are typical issues and how to resolve them:
- Authentication errors: This might occur if using incorrect credentials or if your email provider blocks “less secure apps.” Enable settings that allow SMTP access.
- File not found: Ensure the attachment path is correct. Relative paths should be specified according to the working directory of script execution.
- Email goes to spam: Use verified sender domains, appropriate subject lines, and avoid spam keywords in the body.
Gmail-Specific Considerations
Gmail has strict security policies. To avoid authorization issues:
- Use an App Password instead of your main password.
- Ensure 2-Step Verification is enabled on your account.
- Enable Gmail API for more advanced applications and integrate with Google OAuth.
Alternatively, consider using OAuth 2.0 for more secure and scalable solutions, especially in commercial applications.

Going Beyond SMTP
While SMTP is useful for sending individual or scheduled emails, large-scale or transactional emailing should be handled using dedicated services like:
- SendGrid
- Amazon SES
- Mailgun
- Postmark
These platforms offer better deliverability, analytics, and support for bulk sends. They often provide Python SDKs or RESTful APIs for easy integration.
Conclusion
Sending emails with attachments using Python is both efficient and highly customizable. Whether you’re automating reports, sending notifications, or deploying batch emails, Python paired with SMTP provides a secure and foundational approach. While this guide focuses on standard methods using smtplib and email.mime, don’t hesitate to explore more advanced libraries and APIs as your needs grow more complex.
By adhering to robust coding practices and security guidelines, developers can build reliable email-sending solutions that integrate seamlessly into any larger system.