DEV Community

Cover image for Fake SMTP Server
Nazanin Ashrafi
Nazanin Ashrafi

Posted on

Fake SMTP Server

Step 1: Install aiosmtpd library

pip install aiosmtpd
Enter fullscreen mode Exit fullscreen mode

Step 2: The Modern Fake SMTP Server Script (aioserver.py)

import asyncio
from aiosmtpd.controller import Controller
from aiosmtpd.smtp import SMTP

# --- Define the Handler Class ---
# This class defines what happens when the server receives a message.
class DebuggingHandler:
    """
    A modern asynchronous handler that processes and prints received emails.
    """

    async def handle_DATA(self, server, session, envelope):
        """
        Called when the server receives the full email data.
        """
        print("\n=======================================================")
        print("  !!! EMAIL SUCCESSFULLY RECEIVED by FAKE SERVER !!!  ")
        print("=======================================================")
        print(f"  - Client connected from: {session.peer}")
        print(f"  - MAIL FROM: {envelope.mail_from}")
        print(f"  - RCPT TO: {envelope.rcpt_tos}")
        print("--- MESSAGE CONTENT START ---")

        # 'envelope.content' contains the raw email message bytes.
        # We decode it for display.
        print(envelope.content.decode('utf8', errors='replace'))

        print("--- MESSAGE CONTENT END ---")
        print("=======================================================\n")
        # Returning '250 OK' tells the client the message was accepted
        return '250 OK'


# --- Startup Code ---

SERVER_IP = 'localhost'
SERVER_PORT = 1025

async def run_server():
    """
    Starts the asynchronous SMTP server.
    """
    handler = DebuggingHandler()

    # The Controller handles starting and stopping the asyncio event loop.
    controller = Controller(handler, hostname=SERVER_IP, port=SERVER_PORT)

    # Start the server (it runs in the background)
    controller.start()

    print("Starting modern fake SMTP server...")
    print(f"Listening on {SERVER_IP}:{SERVER_PORT}...")
    print("Leave this window open.")
    print("Press Ctrl+C to stop the server and exit.")

    # Keep the main thread alive so the server can run
    while True:
        await asyncio.sleep(1)

if __name__ == "__main__":
    try:
        # Start the asyncio event loop
        asyncio.run(run_server())
    except KeyboardInterrupt:
        print("\nModern fake server stopped.")
Enter fullscreen mode Exit fullscreen mode

Step 3: The Client Script (client_script.py)

import smtplib
from email.mime.text import MIMEText

# Use the same IP and PORT as your fake_server.py
FAKE_SERVER_IP = 'localhost'
FAKE_SERVER_PORT = 1025

# --- Email Details ---
SENDER_EMAIL = 'my_modern_test_address@fake.com'
RECIPIENT_EMAIL = 'recipient_for_learning@test.org'
EMAIL_SUBJECT = 'Modern Test Email from Python smtplib'
EMAIL_BODY = (
    "This message confirms my smtplib script is working against the modern aiosmtpd server.\n"
    "No real email account was used!"
)

# --- Construct the Message ---
# MIMEText is used to properly format the email content and headers.
message = MIMEText(EMAIL_BODY, 'plain', 'utf-8')
message['Subject'] = EMAIL_SUBJECT
message['From'] = SENDER_EMAIL
message['To'] = RECIPIENT_EMAIL


# --- Send the Email using smtplib ---
try:
    print(f"Attempting to connect to modern fake server at {FAKE_SERVER_IP}:{FAKE_SERVER_PORT}...")

    # We use smtplib.SMTP for the simple, local connection
    with smtplib.SMTP(FAKE_SERVER_IP, FAKE_SERVER_PORT) as server:

        # Send the message data
        server.send_message(message)

    print("\n--- SUCCESS ---")
    print("The email was successfully handed off to the modern fake server.")
    print("Check your 'aioserver.py' terminal window for the full message content!")

except Exception as e:
    print("\n--- ERROR ---")
    print(f"An error occurred: {e}")
    print("Ensure 'aioserver.py' is running in a separate terminal window and you ran 'pip install aiosmtpd'.")
Enter fullscreen mode Exit fullscreen mode

Instructions:

  1. Save the new server script as aioserver.py.

  2. Save the client script as client_script.py.

  3. Run the server in one terminal: python aioserver.py

  4. Run the client in a second terminal: python client_script.py


Another script

fake_smtp.py

import asyncio
from aiosmtpd.controller import Controller


class DebugHandler:
    async def handle_DATA(self, server, session, envelope):
        print("\n===== NEW EMAIL RECEIVED =====")
        print(f"From: {envelope.mail_from}")
        print(f"To: {envelope.rcpt_tos}")
        print("----- MESSAGE BODY -----")
        print(envelope.content.decode("utf-8", errors="replace"))
        print("===== END EMAIL =====\n")
        return "250 Message accepted for delivery"


async def main():
    handler = DebugHandler()
    controller = Controller(handler, hostname="localhost", port=1025)
    controller.start()
    print("Fake SMTP server running on localhost:1025")
    try:
        await asyncio.Future()  # Run the event loop forever
    except KeyboardInterrupt:
        controller.stop()


if __name__ == "__main__":
    asyncio.run(main())
Enter fullscreen mode Exit fullscreen mode

test_client.py

import smtplib
from email.mime.text import MIMEText

msg = MIMEText("Hello! This is a test email to the fake SMTP server.")
msg["Subject"] = "Test Email"
msg["From"] = "me@example.com"
msg["To"] = "you@example.com"

with smtplib.SMTP("localhost", 1025) as server:
    server.send_message(msg)

print("Email sent!")
Enter fullscreen mode Exit fullscreen mode

  • Fake server doesn't support it
  • Fake server doesn't require auth
  • localhost:1025
# No TLS, no login (fake server doesn't support it)
# connection.starttls()  <-- remove
# connection.login(user=my_email, password=password)  <-- remove
Enter fullscreen mode Exit fullscreen mode

Note: This is AI generated and its only purpose is to help me and maybe someone else will find this useful as well.

Top comments (0)