Search code examples
pythonemailoutlooksmtpsmtplib

smtplib error: Unknown Protocol for Automated Outlook Email with Attachment


I'm trying to send a basic email with an attached document. The example I have works fine with a google address smtp.google.com, but when I try changing it over to smtp.office365.com, I get this error: [SSL: UNKNOWN_PROTOCOL] unknown protocol (_ssl.c:852).

This is a domain email that runs through the office365 SMTP server as a host for the email service. I've checked with the IT team, and they have turned on SMTP authentication on the account.

Obviously, this has been done before, so I have checked my code against this example, but don't see any obvious differences that could be causing it. I've also doubled checked the smtplib documentation, and smtp.office365.com is a valid, recognized SMTP address.

I've written this out as follows (note the confidential credentials which prevent a minimal reproducible example). I've noted where the error occurs, it's almost like smtplib is not recognizing the office365 SMTP address.

    def send_email(self, html_message):
            # Create a text/plain message
    
            formatted_date = datetime.datetime.now().strftime('%Y%m%d')
    
            msg_root = MIMEMultipart('related')
            msg_root['Subject'] = self.client.client_name + 'Test Forecast'
            msg_root['From'] = self.config.get_email_from
            recipients = self.client.recipient_email
            recipients = recipients.split(', ')
    
            body = MIMEText(html_message, 'html')
            msg_root.attach(body)
    
            filename = self.client.city + ', ' + self.client.state
    
            # PDF attachment
            if self.client.use_pdf:
                filepath = self.config.get_email_pdf_file_path
                fp = open(filepath, 'rb')
                att = email.mime.application.MIMEApplication(fp.read(), _subtype="pdf")
                fp.close()
                att.add_header('Content-Disposition', 'attachment', filename=filename + '.pdf')
                msg_root.attach(att)
    
            # SSL port config
            port = 587
    
            # Create a secure SSL context
            context = ssl.create_default_context()
    
            # Connect
            with smtplib.SMTP_SSL("smtp.office365.com", port, context=context) as server: # Error on this line
                server.ehlo()
                server.starttls()
                server.login(self.config.get_email_from, self.config.get_email_password)
                print("Sending email report...")
                # Send email
                server.sendmail(self.config.get_email_from, recipients, msg_root.as_string())
            print("Your email was sent!")

Solution

  • It appears that because Microsoft uses port 587 for SMTP and the external domain we're using doesn't communicate via SSL, I had to change the port over to 587, remove the SSL argument from the method, and remove the context. With it now using SMTP rather than SSL, starttls was also necessary.

    The working version looks like this:

        port = 587
    
        # Connect
        with smtplib.SMTP("smtp.office365.com", port) as server:
            server.ehlo()
            server.starttls()
            server.ehlo()
            server.login(self.config.get_email_from, self.config.get_email_password)
            print("Sending email report...")
            # Send email
            server.sendmail(self.config.get_email_from, recipients, msg_root.as_string())
            print("Your email was sent!")