Mastering Email Automation with Python: A Complete Guide to Sending Emails
Email automation is one of the most practical and widely-used Python applications. Whether you're sending reports, alerts, or notifications, Python can help streamline and automate the process with just a few lines of code.
In this guide, you’ll learn how to send emails using Python with smtplib and email libraries. We'll also cover sending HTML emails, adding attachments, and using Gmail SMTP.
1. Prerequisites
Before you start, make sure Python is installed and the following libraries are available:
pip install secure-smtplib
You’ll also need:
- A working email address (Gmail is used in this example)
- App password if using Gmail (recommended over your actual password)
2. Sending a Simple Email Using Python
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
sender_email = "[email protected]"
receiver_email = "[email protected]"
password = "your_app_password"
# Create the email content
message = MIMEMultipart()
message["From"] = sender_email
message["To"] = receiver_email
message["Subject"] = "Test Email from Python"
body = "Hello, this is a test email sent from Python!"
message.attach(MIMEText(body, "plain"))
# Send the email
with smtplib.SMTP("smtp.gmail.com", 587) as server:
server.starttls()
server.login(sender_email, password)
server.sendmail(sender_email, receiver_email, message.as_string())
print("Email sent successfully!")3.Sending HTML Emails
Want to send a nicely formatted email?
html_content = """
<html>
<body>
<h2 style='color:blue;'>Hello from Python!</h2>
<p>This is an <b>HTML</b> email.</p>
</body>
</html>
"""
message.attach(MIMEText(html_content, "html"))Just replace the MIMEText(body, "plain") line with this HTML section.
4. Sending Emails with Attachments
from email.mime.base import MIMEBase
from email import encoders
filename = "document.pdf"
with open(filename, "rb") as attachment:
part = MIMEBase("application", "octet-stream")
part.set_payload(attachment.read())
encoders.encode_base64(part)
part.add_header("Content-Disposition", f"attachment; filename= {filename}")
message.attach(part)5. Using Gmail SMTP Securely
Important Note for Gmail Users:
- Use an App Password instead of your Gmail password.
- Enable 2-Step Verification on your Google Account and generate a secure app-specific password.
Learn more here: Google App Passwords
The Google App Password is now used to set up the SMTP plugins or applications. A 16-digit App Password is used to grant access to a less secure app or device with your Google Account. Two-factor authentication (2FA) is required to utilize an app password.
In case you do not have the two-factor authentication (2FA) enabled already, you will find the setup guide at the end of this article.
If the application you want to use doesn’t have the “Sign in with Google” option or after the 2-Step-Verification you get an “incorrect password” error, you can try setting up an App Password in order to log in.
Create and use App Passwords
1. Access the MyAccount page at: https://myaccount.google.com.
2. Click on Security.
3. Access 2-step verification located under “Signing in to Google.” (verify 2-step verification if need done)
4. Log in with your Google Workspace with username and password.
5.Search on top (app password) and select App Passwords
6. Enter the App Name, then click Create.
7. Copy the App password
Note: Google will revoke your App Passwords when you change your Google Account password. You’ll need to generate a new App Password.
6. Common Errors and Troubleshooting
| Error | Cause | Solution |
|---|---|---|
smtplib.SMTPAuthenticationError | Wrong credentials | Use app password instead |
smtplib.SMTPServerDisconnected | Server dropped the connection | Use server.ehlo() and server.starttls() |
| Email goes to Spam | Gmail filters it | Use proper subject and content formatting |
How to send Email Using Sendgrid
# pip install sendgrid
from sendgrid import SendGridAPIClient
from sendgrid.helpers.mail import Mail
from typing import Optional
import logging
# Configure a logger for logging success or error messages
logger = logging.getLogger(__name__)
def send_mail(
subject: str,
preheader: str,
body: str,
sender_email: str,
redirect_page_url: str,
sendgrid_api_key: str,
recipient_email: str,
token: str,
template_id: str,
meta_data: Optional[dict] = None,
) -> bool:
"""
Sends an email using SendGrid with dynamic template support.
Args:
subject (str): Subject line of the email.
preheader (str): Preheader text (shown in some email clients).
body (str): Main content/body of the email.
sender_email (str): Email address of the sender (must be verified in SendGrid).
redirect_page_url (str): URL the user will be redirected to when clicking the link in the email.
sendgrid_api_key (str): Your SendGrid API key for authentication.
recipient_email (str): Email address of the recipient.
token (str): Token to append as a query param to the URL.
template_id (str): ID of the dynamic template configured in SendGrid.
meta_data (dict, optional): Any extra metadata to pass into the template.
Returns:
bool: True if email was sent successfully, False otherwise.
"""
# Ensure meta_data is a dictionary (prevents mutable default arg issue)
if meta_data is None:
meta_data = {}
# Create a SendGrid Mail object
message = Mail(from_email=sender_email,to_emails=recipient_email,subject=subject)
# Attach dynamic template and its placeholder data
message.template_id = template_id
message.dynamic_template_data = {
"body": body,
"subject": subject,
"preheader": preheader,
"url": f'{redirect_page_url}?token={token}', # Add token to URL
"meta_data": meta_data, # Optional metadata that your template can access
}
try:
# Initialize SendGrid client with API key
sg = SendGridAPIClient(api_key=sendgrid_api_key)
# Send the email
response = sg.send(message)
# Log success and return True if status code is 200 (OK) or 202 (Accepted)
logger.info(f"Email sent: Status={response.status_code}")
return response.status_code in (200, 202)
except Exception as e:
# Log any errors that occurred while sending the email
logger.error(f"SendGrid email sending failed: {e}")
return FalseSend simple Plain Text
import logging
from sendgrid import SendGridAPIClient
from sendgrid.helpers.mail import Mail
def send_email_via_sendgrid(
sendgrid_api_key: str,
sender_email: str,
receiver_email: str,
subject: str,
message: str
) -> bool:
"""
Sends an email using the SendGrid API.
Parameters:
sendgrid_api_key (str): Your SendGrid API key.
sender_email (str): The email address of the sender.
receiver_email (str): The recipient's email address.
subject (str): The subject of the email.
message (str): The plain text content of the email.
Returns:
bool: True if the email was sent successfully, False otherwise.
"""
mail = Mail(
from_email=sender_email,
to_emails=receiver_email,
subject=subject,
plain_text_content=message,
)
try:
sg = SendGridAPIClient(api_key=sendgrid_api_key)
response = sg.send(mail)
logging.info("Email sent. Status code: %s", response.status_code)
return True
except Exception as e:
logging.exception("Failed to send email: %s", str(e))
return False
