Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unexpected server response in "DATA_RECEIVED" state #534

Open
RajdeepMondal opened this issue Jan 10, 2025 · 0 comments
Open

Unexpected server response in "DATA_RECEIVED" state #534

RajdeepMondal opened this issue Jan 10, 2025 · 0 comments

Comments

@RajdeepMondal
Copy link

I am sending message requests to an SMTP server and analysing the response from the server.
I have the following setup for aiosmtpd.
server.py:

import asyncio
from aiosmtpd.controller import Controller

class CustomSMTPHandler:

    async def handle_DATA(self, server, session, envelope):
        print(f"Message from: {envelope.mail_from}")
        print(f"Message to: {envelope.rcpt_tos}")
        print(f"Message data:\n{envelope.content.decode('utf-8')}")
        return '250 OK'

# Run the SMTP server
controller = Controller(CustomSMTPHandler(), hostname='127.0.0.1', port=8025)
controller.start()

print("SMTP server is running on port 8025...")

try:
    asyncio.get_event_loop().run_forever()

except KeyboardInterrupt:
    controller.stop()
    print("SMTP server stopped.")

client.py:

import smtplib
import json
from tqdm import tqdm

def run_smtp_tests(server_address, port, tests_file, output_file):
    # Load test cases from the JSON file
    with open(tests_file, "r") as f:
        test_cases = json.load(f)
    
    results = []

    count = 0
    # Loop through each test case
    for test in tqdm(test_cases):
        count += 1
        input_seq, state, test_input = test
        print(f"Running test {count} for state: {state}, input: {test_input}")
        print(f"test case: {test}\n")
        total_input_seq = input_seq + [test_input]

        try:
            # Connect to the SMTP server
            server = smtplib.SMTP(server_address, port)
            
            # Execute input sequence to reach the desired state
            for input in total_input_seq:
                print(f"Input: {input}")
                if input == "EHLO":
                    response = server.ehlo()
                elif input == "HELO":
                    response = server.helo()
                elif input == "MAIL FROM:":
                    response = server.mail("[email protected]")
                elif input == "RCPT TO:":
                    response = server.rcpt("[email protected]")
                elif input == "DATA":
                    response = server.docmd("DATA")
                    server.send("Hi\r\n.\r\n")
                elif input == ".":
                    server.send("\r\n.\r\n")
                    response = server.getreply()
                elif input == "QUIT":
                    response = server.quit()
                else:
                    server.send(f"{input}\r\n")
                    response = server.getreply()

                print(f"Response: {response}")
            
            results.append((state, test_input, response))
        except Exception as e:
            results.append((state, test_input, str(e)))
        finally:
            # Quit the server connection
            try:
                server.quit()
            except:
                pass

    # Save results to the output file
    with open(output_file, "w") as f:
        for result in results:
            f.write(f"{result}\n")

# Example Usage
run_smtp_tests(
    server_address="127.0.0.1",
    port=8025,
    tests_file="tests.json",
    output_file="results.txt"
)

Save the following test case in tests.json in the same directory:

[
	[
        	[
            		"HELO",
            		"MAIL FROM:",
            		"RCPT TO:",
            		"DATA"
        	],
        	"DATA_RECEIVED",
        	"."
        ]
]

I get the following responses from the aiosmtpd server:

Input: HELO
Response: (250, b'rajdeep')
Input: MAIL FROM:
Response: (250, b'OK')
Input: RCPT TO:
Response: (250, b'OK')
Input: DATA
Response: (354, b'End data with <CR><LF>.<CR><LF>')
Input: .
Response: (250, b'OK')

I also ran the test case on opensmtpd but got a different set of responses:

Input: HELO
Response: (250, b'rajdeep Hello [127.0.1.1] [127.0.0.1], pleased to meet you')
Input: MAIL FROM:
Response: (250, b'2.0.0 Ok')
Input: RCPT TO:
Response: (250, b'2.1.5 Destination address valid: Recipient ok')
Input: DATA
Response: (354, b'Enter mail, end with "." on a line by itself')
Input: .
Response: (550, b'5.7.1 Delivery not authorized, message refused: Message is not RFC 2822 compliant')

If you look at the final opensmtpd response, it returns an error code 550, but aiosmtpd accepts it. Why is there a discrepancy?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant