0

I am coding an assignment and got the code to successfully send an email to my email address. How can I correctly use a loop to ask the user if they want to send another email or quit. You can see how I attempted this but it doesn't seem to work. Additionally, How do I make it ask them to log into their outlook account and/or ask them the email address of the recipient?

Many thanks for taking time to read

This is the code:

from socket import *
import ssl
import base64

# Some global variables
SMTP_MAIL_SERVER = 'smtp-mail.outlook.com'
SMTP_TLS_PORT = 587
END_MESSAGE = '\r\n.\r\n'

client_socket = None
ssl_context = None


def send_line(line):
    global client_socket
    print('CLIENT: ' + line.strip())
    client_socket.send(line.encode())
    response = client_socket.recv(1024).decode()
    return response


def get_code(response):
    return int(response[:3])


def connect():
    global client_socket
    global ssl_context
    print('CLIENT: Connecting to ' + SMTP_MAIL_SERVER)
    client_socket = socket(AF_INET, SOCK_STREAM)
    client_socket.connect((SMTP_MAIL_SERVER, SMTP_TLS_PORT))
    response = client_socket.recv(1024).decode()
    return response


def send_ehlo():
    helo = 'ehlo smtp-mail.outlook.com\r\n'
    return send_line(helo)


def send_helo():
    helo = 'helo smtp-mail.outlook.com\r\n'
    return send_line(helo)


def start_tls():
    global client_socket
    global ssl_context
    response = send_line('STARTTLS \r\n')
    ssl_context = ssl._create_stdlib_context()
    client_socket = ssl_context.wrap_socket(client_socket, server_hostname=SMTP_MAIL_SERVER)
    return response


def send_auth_request():
    return send_line('auth login \r\n')


def send_username(username):
    as_bytes = username.encode('ascii')
    as_b64 = base64.b64encode(as_bytes)
    as_utf8 = as_b64.decode('utf-8')
    return send_line(as_utf8 + '\r\n')


def send_password(password):
    as_bytes = password.encode('ascii')
    as_b64 = base64.b64encode(as_bytes)
    as_utf8 = as_b64.decode('utf-8')
    return send_line(as_utf8 + '\r\n')


'''--------------------------------------------------------------------------------
TODO - Implement the functions below this point in order to send a test
       email successfully using SMTP commands  
--------------------------------------------------------------------------------'''

def send_mail_from(sender):
    mail_from = 'MAIL FROM: <' + sender + '>\r\n'
    return send_line(mail_from)

def send_rcpt_to(recipient):
    rcpt_to = 'RCPT TO: <' + recipient + '>\r\n'
    return send_line(rcpt_to)

def send_begin_data():
    return send_line('DATA \r\n')

def send_message(subject, message):
    subject_line = 'Subject: ' + subject + '\r\n'
    body = '\nMessage:' + message + '\r\n'

    return send_line(subject_line + body + END_MESSAGE)

def send_quit():
    return send_line('QUIT \r\n')


'''--------------------------------------------------------------------------------
TODO - Implement the functions above this point in order to send a test
       email successfully using SMTP commands  
--------------------------------------------------------------------------------'''

send_email_question = 1
while send_email_question == 1:
    def send_one_email():


            # Open a TCP connection - the reply should start '220'
            reply = connect()
            print('SERVER: ' + reply)
            # Send a EHLO command - the reply should be a list of supported
            # 'enhanced' SMTP functions each starting '250'
            reply = send_ehlo()
            print('SERVER: ' + reply)
            # Ask the server to switch to TLS - reply should start '220'
            reply = start_tls()
            print('SERVER: ' + reply)
            # Send a HELO command encrypted - reply should start '220'
            reply = send_helo()
            print('SERVER: ' + reply)
            # Send an AUTH LOGIN command
            reply = send_auth_request()
            print('SERVER: ' + reply)
            # Send your (base64 encoded username) -
            reply = send_username('#sending email username')
            print('SERVER: ' + reply)
            # Send your (base64 encoded username) -
            reply = send_password('#sending email password')
            print('SERVER: ' + reply)
            # Send MAILFROM command - TODO - YOU IMPLEMENT THE FUNCTION BELOW
            reply = send_mail_from('#sending email') #sending email
            print('SERVER: ' + reply)
            # Send RCPT TO command - TODO - YOU IMPLEMENT THE FUNCTION BELOW
            reply=send_rcpt_to('#target email') #target email
            print('SERVER: ' + reply)
            # Send DATA command - TODO - YOU IMPLEMENT THE FUNCTION BELOW
            reply = send_begin_data()
            print('SERVER: ' + reply)
            # Send the message (including subject) - TODO - YOU IMPLEMENT THE FUNCTION BELOW
            reply = send_message(subject='Nothing much', message='Hello World')
            print('SERVER: ' + reply)
            # Quit the SMTP session - TODO - YOU IMPLEMENT THE FUNCTION BELOW
            user_end_question = int(input("Please enter 1 if you would like to send another email 0 to end connection: "))
            if user_end_question == 0:
                reply = send_quit()
                print('SERVER: ' + reply)



if __name__ == '__main__':
    send_one_email()
  • You seem to be reinventing the built-in [`smtplib` module](https://docs.python.org/3/library/smtplib.html) from first principles. Probably don't do that. Rather, throw away what you have and start over with the [examples from the `email` documentation.](https://docs.python.org/3/library/email.examples.html) – tripleee Jan 05 '23 at 07:07

1 Answers1

0

When doing :

send_email_question = 1
while send_email_question == 1:
    def send_one_email():
        # ... [snip lots of send/reply]
        user_end_question = int(input("Please enter 1 if you would like to send another email 0 to end connection: "))
        if user_end_question == 0:
            reply = send_quit()
            print('SERVER: ' + reply)

if __name__ == '__main__':
    send_one_email()

you are entering the loop, which creates a function (one def instruction). Then in the if __name__ you call one time the function which was created.

Instead, you should do :

def send_one_email():
    # ... [snip lots of send/reply]

if __name__ == '__main__':
    send_email_question = 1
    while send_email_question == 1:
        send_one_email()
        user_end_question = int(input("Please enter 1 if you would like to send another email 0 to end connection: "))
        if user_end_question == 0:
            reply = send_quit()
            print('SERVER: ' + reply)

which is creating the function (only once), then in a loop sending an email and asking whether to quit. This way, the send_one_email just sends one email, and do nothing else. And your "main" part decides how many times to call it.

99% of the time, you don't want to create functions (def) inside loops.

Lenormju
  • 4,078
  • 2
  • 8
  • 22
  • (Tangentially, code you put in `if __name__ == '__main__':` should be trivial; the purpose of this boilerplate is to allow you to `import` the code, which you will not want to do anyway if the logic you need is not available via `import`. See also https://stackoverflow.com/a/69778466/874188) – tripleee Jan 05 '23 at 07:05
  • 1
    I did not want to dwell on it, but what I usually do myself is create a `main() -> int` function, and my `if __name__ == "__main__"` just do `sys.exit(main())`. It also prevents variables declared in the `if` to be globals :) – Lenormju Jan 05 '23 at 07:19
  • 1
    Thank you, now I see how simple of a mistake it was, also to respond to the further tips, most of this was coded by my teacher, I just had to implement the functions but wanted to go a step further and ask the user if it wanted to repeat the process and now will continue to make it so it can ask for email addresses and different messages. Many thanks! – Corroxin Gaming Jan 08 '23 at 16:28