SMTP Mail Client Python

11,313

The most likely problem is this one:

mailfromCommand = 'MAIL FROM: <[email protected]>\r\n.'

Notice the extra . at the end? So, what you're sending the server ends up being:

MAIL FROM: <[email protected]>
.RCPT TO: <[email protected]>

And .RCPT is a syntax error.


However, there are two other very serious problems in the code.

The first is that there's no guarantee that send sends all the data you give it. That's why it returns the number of bytes actually sent. So, you could easily have ended up sending it part of a command.

This one is trivial to solve: just use sendall instead of send.


The second is that there's no guarantee that each recv will get exactly one line of data. It may get 6 characters in one recv, then 19 lines in the next. TCP sockets are byte streams, not message streams, and it's up to you to build a message stream on top of it for your protocol.

Imagine what happens if you get 250 [email protected] Addr in one recv, and then ess OK\r\n250 [email protected] Address OK\r\n in the next. You're going to check whether the second one starts with 250, find that it doesn't, and fail.

This one is not quite as trivial to solve in general—normally you have to buffer and parse out messages, which means either writing a generator, or reorganizing your code completely.

But in the case of line-by-line protocols like SMTP, it's easy: just use makefile, which gives you back a file object that you can iterate over or call readline on, and it will magically handle the buffering for you.


It looks like all three of these bugs are apparently in the code your teacher gave you. Not to mention things like the stray semicolon at the end of helloCommand = 'HELO Alice\r\n' (which is a red flag for code written by someone who doesn't actually know Python). You may want to read the Socket Programming HOWTO, or, better, a more complete tutorial (that Google can hopefully find for you) so you learn how to actually write working programs instead of broken nonsense that works almost 99% of the time on localhost on your platform when the computer's not too busy.

Share:
11,313
Admin
Author by

Admin

Updated on June 04, 2022

Comments

  • Admin
    Admin almost 2 years

    I have to write a SMTP mail client in Python for class and am stuck on the first part of the assignment. After much hassle I've gotten this far (using Free Portable SMTP server currently but will later need to use SSL or TLS for gmail). Below is my code. I get a 500 Syntax error when it gets to the RCPT TO part of the code. Can anyone help?

    from socket import *
    msg = "\r\n I love computer networks!"
    endmsg = "\r\n.\r\n"
    
    # Choose a mail server
    mailServer = 'localhost'
    mailPort = 25
    
    # Create socket called clientSocket and establish a TCP connection with mailserver
    clientSocket = socket(AF_INET,SOCK_STREAM)
    clientSocket.connect((mailServer, mailPort))
    recv = clientSocket.recv(1024)
    print 'test'
    print recv
    if recv[:3] != '220':
        print '220 reply not received from server.'
    
    # Send HELLO command and print server response.
    helloCommand = 'HELO Alice\r\n';
    clientSocket.send(helloCommand)
    recv1 = clientSocket.recv(1024)
    print recv1
    if recv1[:3] != '250':
        print '250 reply not received from server.'
    
    # Send MAIL FROM command and print server response.
    #command = "STARTTLS\r\n"
    #clientSocket.send(command)
    #recva = clientSocket.recv(1024)
    #print(recva)
    mailfromCommand = 'MAIL FROM: <[email protected]>\r\n.'
    clientSocket.send(mailfromCommand)
    recv1 = clientSocket.recv(1024)
    print(recv1)
    if recv1[:3] != '250':
        print('mail from 250 reply not received from server.')
    
    # Send RCPT TO command and print server response.
    rcpttoCommand = 'RCPT TO: <[email protected]>\r\n'
    clientSocket.send(rcpttoCommand)
    recv1 = clientSocket.recv(1024)
    print(recv1)
    if recv1[:3] != '250':
        print('rcpt to 250 reply not received from server.')
    
    # Send DATA command and print server response
    dataCommand = 'Data'
    print(dataCommand)
    clientSocket.send(dataCommand)
    recv1 = clientSocket.recv(1024)
    print(recv1)
    if recv1[:3] != '250':
        print('data 250 reply not received from server.')
    
    # Send message data.
    message = raw_input('Enter Message Here: ')
    
    # Fill in end# Message ends with a single period.
    mailMessageEnd = '\r\n.\r\n'
    clientSocket.send(message + mailMessageEnd)
    recv1 = clientSocket.recv(1024)
    print(recv1)
    if recv1[:3] != '250':
        print('end msg 250 reply not received from server.')
    
    # Send QUIT command and get server response.
    quitCommand = 'Quit\r\n'
    print(quitCommand)
    clientSocket.send(quitCommand)
    recv1 = clientSocket.recv(1024)
    print(recv1)
    if recv1[:3] != '250':
        print('quit 250 reply not received from server.')
    
        pass
    
    if __name__ == '__main__':
        main()
    

    Results:

    test
    220 localhost
    
    
    250 Hello localhost
    
    
    250 [email protected] Address Okay
    
    
    RCPT TO: <[email protected]>
    
    
    500 Syntax Error
    
    
    rcpt to 250 reply not received from server.
    Data