How to Send Emails in Python from Scratch in 2024
This article will teach you how to send and receive emails in Python using Google’s SMTP server without using the ‘smtplib’ Python library.
What is SMTP?
SMTP (Simple Mail Transfer Protocol) is a software protocol for sending simple text-based emails. It works by:
- Connecting to an SMTP Server
- Sending and Receiving Initial Greetings and Commands
- Logging into your Gmail Account
- Writing and Sending the Subject and Body of the Email
SMTP originated in 1982 with RFC 821, but has now evolved into Extended SMTP (ESMTP) through RFC iterations 821 -> 1869 -> 2821 -> 5321 -> 7504. I will be mostly using RFC 5321 in this article.
How does SMTP work?
SMTP works by:
- Connecting to an SMTP server
- Sending and Receiving Initial Greetings and Commands
- Logging into your Gmail Account
- Writing and Sending the Subject and Body of the Email
Here is a graphic I made using Canva:
How to Send an Email in Python
Before starting, we need to import the ‘socket’, ‘ssl’, and ‘base64’ libraries for later:
import socket
import ssl
import base64
First, we must connect to Google’s SMTP server through its IP address. Google’s SMTP server is called “smtp.gmail.com”, and we will use the socket class’s ‘socket’ library to create a TCP connection. We will be connecting to the encrypted, and safe, Port 587 (although traditionally Port 25 was used for SMTP emails in the past, it is HIGHLY recommended NOT to use it because Port 25 is not encrypted and your information will get stolen):
import socket
import ssl
import base64
def main():
smtp_server = 'smtp.gmail.com'
ip_address = socket.gethostbyname(smtp_server) #finds the IP address of Google's SMTP server
smtp_port = 587 #the SSL encrypted connection
# Establish a TCP connection to the SMTP server
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect((ip_address, smtp_port))
As soon as the above “client_socket.connect((ip_address, smtp_port))” code is executed and correctly connects to the server, the server will send an initial reply to your computer, such as:
220 smtp.gmail.com ESMTP af79cd13be357-7955a81dc14sm304665385a.45 – gsmtp
Where ‘220’ is a positive reply code, ‘smtp.gmail.com’ is the domain name of the SMTP server, ‘ESMTP’ is the version of SMTP this server is running, ‘af79….45’ is the unique ID of this message, and ‘gsmtp’ indicates that this response is from a Google SMTP server.
NOTE: Although the ‘220’ reply code is standardized, each company’s SMTP server has its unique initial reply message.
To receive the initial message from the server, you must call the ‘.recv’ method from your socket that is connected to the SMTP server in this ‘initiate_connection’ method:
import socket
import ssl
import base64
def initiate_connection(client_socket):
#server sends some of its information when connecting to it via TCP
print("v-----initiate connection-----v")
server_greeting = client_socket.recv(1024) #reads in max of 1024 bytes from server
print(server_greeting.decode()) #decodes received message in bytes into a string
print("^-----initiate connection-----^")
def main():
smtp_server = 'smtp.gmail.com'
ip_address = socket.gethostbyname(smtp_server) #finds the IP address of Google's SMTP server
smtp_port = 587 #the SSL encrypted connection
# Establish a TCP connection to the SMTP server
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect((ip_address, smtp_port))
initiate_connection(client_socket)
You now must enter a