Python

Mastering Email Automation with Python: A Complete Guide to Sending Emails

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

ErrorCauseSolution
smtplib.SMTPAuthenticationErrorWrong credentialsUse app password instead
smtplib.SMTPServerDisconnectedServer dropped the connectionUse server.ehlo() and server.starttls()
Email goes to SpamGmail filters itUse 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 False

Send 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

About author

author image

Amrit panta

Fullstack developer, content creator



Scroll to Top