pythonpython-3.xsmtpicloudsmtplib

Sending Email with iCloud in Python


I am trying to send some emails from an iCloud email address using the code below:

import smtplib


def main():
    smtp_obj = smtplib.SMTP('smtp.mail.me.com', 587)
    smtp_obj.starttls()
    smtp_obj.login('user@icloud.com', 'password')

    pairs = {'name_1': 'email_1@gmail.com', 'name_2': 'email_2@gmail.com'}

    try:
        for name in pairs.keys():
            body = 'hi {}'.format(name)
            print('Sending email to {}...'.format(name))
            send_status = smtp_obj.sendmail(smtp_obj.user, pairs.get(name), body)

            if send_status != {}:
                print('There was a problem sending mail to {}.\n{}'.format(name, send_status))
    except smtplib.SMTPDataError:
        print('Sending email to {} failed.'.format(name))
    finally:
        smtp_obj.quit()


if __name__ == '__main__':
    main()

However, when I run this, I only get an SMTPDataError, saying,

smtplib.SMTPDataError: (550, b'5.7.0 From address is not one of your addresses')

I've tried hardcoding different addresses. When I use my address, I get this. When I use an address I know to be wrong, the error message also prints out the invalid email (which this account would have no way to access - for instance, listing an un-logged-into gmail address to see what happens).

Does anyone know what's going on here?

Thanks!


Solution

  • I solved this problem. As it turns out, the "from" and "to" addresses must be provided as part of the message body for icloud to send the email.

    The code segment I was missing is the following:

    try:
        for name in pairs.keys():
            msg = ('From: {}\r\nTo: {}\r\n\r\nHi, {}'.format(smtp_obj.user,
                                                             pairs.get(name),
                                                             name))
    
            print('Sending email to {} at {}...'.format(name, pairs.get(name)))
    
            send_status = smtp_obj.sendmail(from_addr=smtp_obj.user,
                                            to_addrs=pairs.get(name),
                                            msg=msg)
    
            if send_status != {}:
                print('There was a problem sending mail to {}.\n{}'.format(name, send_status))
    finally:
        smtp_obj.quit()