How to Send Email in Python: A Comprehensive Guide

How to Send Email in Python
Photo by Mariia Shalabaieva on Unsplash

How to Send Email in Python: A Comprehensive Guide

Sending emails programmatically is a common requirement for many applications, whether for sending notifications, alerts, or testing purposes. Python, a versatile and powerful language, makes this task straightforward with built-in libraries and additional packages. In this article, we’ll explore various ways to send email in Python, from basic text emails to more complex HTML emails with attachments.

Why Sending Emails Programmatically is Important

Emails are a reliable way to communicate with users or notify them of important events. For instance, you might want to send a confirmation email after a user registers on your site, or you may need to notify your team about a critical error in your application. Automating this process saves time and ensures that emails are sent consistently and promptly.

Python provides several methods to send emails, with the smtplib library being the most commonly used. We’ll start with the basics and gradually move to more advanced techniques.

Sending Simple Text Emails Using smtplib

The smtplib module in Python defines an SMTP client session object that can be used to send email in Python to any Internet machine with an SMTP or ESMTP listener daemon.

Here’s a simple example:

import smtplib
from email.mime.text import MIMEText

# Define email sender and receiver
sender = "youremail@example.com"
receiver = "receiveremail@example.com"

# Set up the MIMEText object with the message content
message = MIMEText("Hello, this is a test email sent from Python!")
message['Subject'] = 'Test Email'
message['From'] = sender
message['To'] = receiver

# Set up the SMTP server connection
# For Gmail
smtp_server = "smtp.gmail.com"

# For Outlook
# smtp_server = "smtp.office365.com"

port = 587
password = "yourpassword"  # Use app password for Gmail if 2FA is enabled

try:
    # Connect to the SMTP server
    server = smtplib.SMTP(smtp_server, port)
    server.starttls()  # Secure the connection
    server.login(sender, password)  # Log in to the server
    
    # Send the email
    server.sendmail(sender, receiver, message.as_string())
    print("Email sent successfully!")

except Exception as e:
    print(f"Error: {e}")

finally:
    server.quit()  # Close the server connection

In this example, we:

  • Import the necessary modules.
  • Create the email content using MIMEText.
  • Define the sender and receiver.
  • Set up the SMTP server and send email in Python.

Sending HTML Emails

Sometimes, you might want to send more visually appealing emails, which can be achieved by sending HTML content instead of plain text. The process is quite similar to sending plain text emails.

import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

sender = "youremail@example.com"
receiver = "receiveremail@example.com"

# Create the root message
message = MIMEMultipart("alternative")
message['Subject'] = 'HTML Test Email'
message['From'] = sender
message['To'] = receiver

# Create the plain-text and HTML version of your message
text = """
Hi,
This is a plain-text version of the email.
"""

html = """
<html>
  <body>
    <p>Hi,<br>
       This is an <b>HTML</b> version of the email.</p>
  </body>
</html>
"""

# Convert these into MIMEText objects
part1 = MIMEText(text, "plain")
part2 = MIMEText(html, "html")

# Attach parts into message container.
message.attach(part1)
message.attach(part2)

try:
    server = smtplib.SMTP('smtp.example.com', 587)
    server.starttls()
    server.login(sender, "yourpassword")
    server.sendmail(sender, receiver, message.as_string())
    print("HTML Email sent successfully!")
except Exception as e:
    print(f"Error: {e}")
finally:
    server.quit()

Here, we use the MIMEMultipart class to combine both plain text and HTML versions of the email. This ensures that even if the recipient’s email client doesn’t support HTML, they can still see the plain-text version.

Recommended: RAG vs Finetuning

Sending Emails with Attachments

To send attachments, we need to use MIMEBase and encoders from the email package.

Let’s walk through an example of How to send email in Python with an attachment:

import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders

sender = "youremail@example.com"
receiver = "receiveremail@example.com"

# Create the root message
message = MIMEMultipart()
message['Subject'] = 'Email with Attachment'
message['From'] = sender
message['To'] = receiver

# Attach the body with the msg instance
message.attach(MIMEText("This email contains an attachment!", 'plain'))

# Open the file to be sent
filename = "document.pdf"  # In the same directory as script
attachment = open(filename, "rb")

# Create MIMEBase instance
part = MIMEBase('application', 'octet-stream')
part.set_payload(attachment.read())

# Encode file in base64
encoders.encode_base64(part)

part.add_header('Content-Disposition', f"attachment; filename= {filename}")

# Attach the instance 'part' to instance 'message'
message.attach(part)

try:
    server = smtplib.SMTP('smtp.example.com', 587)
    server.starttls()
    server.login(sender, "yourpassword")
    server.sendmail(sender, receiver, message.as_string())
    print("Email with attachment sent successfully!")
except Exception as e:
    print(f"Error: {e}")
finally:
    server.quit()
    attachment.close()

In this example:

  • We open the file to be attached.
  • We create a MIMEBase object to hold the attachment and encode it using encoders.encode_base64.
  • The file is then attached to the email using the add_header method.

Handling Common Errors

A few common errors can occur when sending emails programmatically, such as incorrect login credentials, server connection issues, or port issues. Here are some common scenarios and how to handle them:

Authentication Errors: Ensure that the email and password are correct. For Gmail, enable “Less secure app access” is enabled, or use OAuth2.

Connection Refused: This usually happens if the SMTP server address or port is incorrect. Double-check these settings.

Timeout: If the server is not responding, it could be due to network issues or incorrect server details.

Here’s how you might handle a timeout exception:

import smtplib

try:
    server = smtplib.SMTP('smtp.example.com', 587)
    server.starttls()
    server.login("youremail@example.com", "yourpassword")
except smtplib.SMTPException as e:
    print(f"SMTP error occurred: {e}")
except TimeoutError:
    print("The server did not respond. Please check your connection and try again.")
finally:
    server.quit()

Using Third-Party Libraries

If you find the smtplib library cumbersome or limited, you can use third-party libraries like yagmail or sendgrid to send email in Python with less boilerplate code.

Using yagmail

import yagmail

yag = yagmail.SMTP('yourgmail@gmail.com', 'yourgmailpassword')

contents = [
    "This is the body of the email",
    "You can also add multiple parts",
]

yag.send('receiveremail@example.com', 'Subject line', contents)

yagmail simplifies the process significantly, especially when sending HTML emails or attachments.

Sending emails with Python is simple, thanks to its built-in smtplib library and various third-party tools. Whether you’re sending a plain text email, an HTML email, or one with attachments, Python’s flexible libraries make automation easy. Knowing how email sending works under the hood will give you better control and help you manage errors more effectively.

In this article, we’ve covered the essentials of sending emails, looked into advanced topics like attaching files, and discussed using Gmail’s SMTP server. With this SMTP know-how, you’re ready to add email functionality to your Python projects smoothly.

Now, let’s explore more about email automation and fine-tune your approach even further.

Sending Bulk Emails

If you need to send emails to a list of recipients, you can modify the basic email-sending logic to loop through a list of email addresses. This can be particularly useful for sending newsletters or notifications to multiple users.

Here’s an example:

import smtplib
from email.mime.text import MIMEText

sender = "youremail@example.com"
password = "yourpassword"
smtp_server = "smtp.example.com"
port = 587

# List of recipients
recipients = ["user1@example.com", "user2@example.com", "user3@example.com"]

# Email content
message = MIMEText("Hello, this is a bulk email!")
message['Subject'] = 'Bulk Email'
message['From'] = sender

try:
    server = smtplib.SMTP(smtp_server, port)
    server.starttls()
    server.login(sender, password)
    
    for receiver in recipients:
        message['To'] = receiver
        server.sendmail(sender, receiver, message.as_string())
        print(f"Email sent to {receiver}")
except Exception as e:
    print(f"Error: {e}")
finally:
    server.quit()

This script sends the same email content to each recipient in the recipients list. If you need to send personalized emails, you could customize the message for each recipient within the loop.

You may like: Python Dataframes

Using Environment Variables for Security

Hardcoding sensitive information like email passwords directly in your scripts is not secure. A better approach is to use environment variables to store these credentials. Here’s how you can implement this:

First, set the environment variables in your system. On Linux or macOS, you can do this in the terminal:

export EMAIL_USER="youremail@example.com"
export EMAIL_PASS="yourpassword"

In Windows, use:

set EMAIL_USER=youremail@example.com
set EMAIL_PASS=yourpassword

Then, modify your Python script to access these variables:

import smtplib
import os
from email.mime.text import MIMEText

# Access credentials from environment variables
sender = os.getenv('EMAIL_USER')
password = os.getenv('EMAIL_PASS')
receiver = "receiveremail@example.com"
smtp_server = "smtp.example.com"
port = 587

message = MIMEText("This email uses environment variables for security.")
message['Subject'] = 'Environment Variables'
message['From'] = sender
message['To'] = receiver

try:
    server = smtplib.SMTP(smtp_server, port)
    server.starttls()
    server.login(sender, password)
    server.sendmail(sender, receiver, message.as_string())
    print("Email sent successfully using environment variables!")
except Exception as e:
    print(f"Error: {e}")
finally:
    server.quit()

By using environment variables, you can keep your credentials out of your source code, which is especially important if you’re working in a collaborative environment or storing your code in version control systems like Git.

You could also Python-decouple utility to get the variables from a .env, in case you have one.

Conclusion

Mastering how to send emails in Python is a handy skill that’s straightforward to implement in several ways. Whether you need to send plain text, HTML emails, attachments, or use a secure OAuth2 connection, Python has the tools to help. We’ve looked into basics with the smtplib library, managing bulk emails, using environment variables for added security, and even tackling more advanced techniques.

Knowing these techniques lets you automate email tasks in your apps and make sure they’re secure and can handle growth. With what you’ve learned from this article, you should be ready to add email features to your Python projects, no matter how complex they are.

Software Engineer | Website | + posts

Talha is a seasoned Software Engineer with a passion for exploring the ever-evolving world of technology. With a strong foundation in Python and expertise in web development, web scraping, and machine learning, he loves to unravel the intricacies of the digital landscape. Talha loves to write content on this platform for sharing insights, tutorials, and updates on coding, development, and the latest tech trends

Leave a Reply

Your email address will not be published. Required fields are marked *