5

I want to send an email using outlook. The code is as follows:

import smtplib
from email.message import EmailMessage

msg = EmailMessage()
msg['From'] = '*******'
msg['Subject'] = 'Some subject here'
msg['To'] = '********'
        
msg.set_content('Some text here')

with smtplib.SMTP_SSL('smtp-mail.outlook.com', 587) as smtp:
    smtp.login('******', '****')
    smtp.send_message(msg)
    print('Email sent!')

I get the following error:

---------------------------------------------------------------------------
SSLError                                  Traceback (most recent call last)
<ipython-input-8-4d5956f55c88> in <module>
      6 msg.set_content('Some text here')
      7 
----> 8 with smtplib.SMTP_SSL('smtp-mail.outlook.com', 587) as smtp:
      9     smtp.login('sender_email', 'password')
     10     smtp.send_message(msg)

~/anaconda/envs/quant2/lib/python3.6/smtplib.py in __init__(self, host, port, local_hostname, keyfile, certfile, timeout, source_address, context)
   1029             self.context = context
   1030             SMTP.__init__(self, host, port, local_hostname, timeout,
-> 1031                     source_address)
   1032 
   1033         def _get_socket(self, host, port, timeout):

~/anaconda/envs/quant2/lib/python3.6/smtplib.py in __init__(self, host, port, local_hostname, timeout, source_address)
    249 
    250         if host:
--> 251             (code, msg) = self.connect(host, port)
    252             if code != 220:
    253                 self.close()

~/anaconda/envs/quant2/lib/python3.6/smtplib.py in connect(self, host, port, source_address)
    334         if self.debuglevel > 0:
    335             self._print_debug('connect:', (host, port))
--> 336         self.sock = self._get_socket(host, port, self.timeout)
    337         self.file = None
    338         (code, msg) = self.getreply()

~/anaconda/envs/quant2/lib/python3.6/smtplib.py in _get_socket(self, host, port, timeout)
   1037                     self.source_address)
   1038             new_socket = self.context.wrap_socket(new_socket,
-> 1039                                                   server_hostname=self._host)
   1040             return new_socket
   1041 

~/anaconda/envs/quant2/lib/python3.6/ssl.py in wrap_socket(self, sock, server_side, do_handshake_on_connect, suppress_ragged_eofs, server_hostname, session)
    405                          suppress_ragged_eofs=suppress_ragged_eofs,
    406                          server_hostname=server_hostname,
--> 407                          _context=self, _session=session)
    408 
    409     def wrap_bio(self, incoming, outgoing, server_side=False,

~/anaconda/envs/quant2/lib/python3.6/ssl.py in __init__(self, sock, keyfile, certfile, server_side, cert_reqs, ssl_version, ca_certs, do_handshake_on_connect, family, type, proto, fileno, suppress_ragged_eofs, npn_protocols, ciphers, server_hostname, _context, _session)
    815                         # non-blocking
    816                         raise ValueError("do_handshake_on_connect should not be specified for non-blocking sockets")
--> 817                     self.do_handshake()
    818 
    819             except (OSError, ValueError):

~/anaconda/envs/quant2/lib/python3.6/ssl.py in do_handshake(self, block)
   1075             if timeout == 0.0 and block:
   1076                 self.settimeout(None)
-> 1077             self._sslobj.do_handshake()
   1078         finally:
   1079             self.settimeout(timeout)

~/anaconda/envs/quant2/lib/python3.6/ssl.py in do_handshake(self)
    687     def do_handshake(self):
    688         """Start the SSL/TLS handshake."""
--> 689         self._sslobj.do_handshake()
    690         if self.context.check_hostname:
    691             if not self.server_hostname:

SSLError: [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:852)
1
  • I updated my answer. BTW are you using a free outlook account or an enterprise one? Commented Nov 15, 2021 at 21:32

3 Answers 3

3
+100

Microsoft Outlook uses STARTTLS when sending an email. So you need to replace smtplib.SMTP_SSL with smtplib.SMTP and you need to call starttls

reference: smtplib.SMTP.starttls

import smtplib
from email.message import EmailMessage

sender = '[email protected]'
recipient = '[email protected]'

msg = EmailMessage()
msg.set_content('this is a test')
msg['From'] = '[email protected]'
msg['To'] = '[email protected]'
msg['Subject'] = 'test email'

with smtplib.SMTP('smtp.office365.com', 587) as server:
    server.ehlo()
    server.starttls()
    server.ehlo()
    server.ehlo()
    server.login('your_login', "your_password", initial_response_ok=True) 
    server.ehlo()
    server.sendmail(sender, recipient, msg.as_string())
    print('Email sent!')
    server.close()

Here is the Outlook message in my Gmail account.

enter image description here

enter image description here

I noted that I had to change my Outlook password, because it had a \n, which Python read as a new line.

----------------------------------------
My system information
----------------------------------------
Platform:       macOS
OS Version:     10.15.7
Python Version: 3.9
----------------------------------------

Your question didn't identity the type of Outlook account you have.

  1. Free account
  2. Corporate account

You stated in the comments below that your error message included ask your email administrator. I haven't seem this message with the Free account so I'm assuming that you might have a Corporate account. If you do have the latter please review this Enable or disable authenticated client SMTP submission, because an email administrator would need to enable Authenticated SMTP on your corporate account.

Sign up to request clarification or add additional context in comments.

4 Comments

It threw me an error saying "Can't authenticate" and ask your email administrator
@EchchamaNayak I updated my answer. I was able to send an email with this answer multiple times from my Outlook account to my Gmail one.
I am indeed using a corporate account, I am sorry for having forgotten mentioning it
Yes, that was an important detail that would have reduced the work effort on this bounty question. Hopefully, you were able to persuade your administrator to enable this capability for you.
2

The answer from user "Life is complex" is almost right. I would like to add few more things from myside which might help. I am not very sure which python version you are using here. I am guessing it as Python 3.X. You need to go through based on actual version of python you are using in your case.

From Python smtplib documents, link. Please check which python version you are using with below guide line.

class smtplib.SMTP_SSL(host='', port=0, local_hostname=None, keyfile=None, certfile=None, [timeout, ]context=None, source_address=None) An SMTP_SSL instance behaves exactly the same as instances of SMTP. SMTP_SSL should be used for situations where SSL is required from the beginning of the connection and using starttls() is not appropriate. If host is not specified, the local host is used. If port is zero, the standard SMTP-over-SSL port (465) is used. The optional arguments local_hostname, timeout and source_address have the same meaning as they do in the SMTP class. context, also optional, can contain a SSLContext and allows configuring various aspects of the secure connection. Please read Security considerations for best practices.

keyfile and certfile are a legacy alternative to context, and can point to a PEM formatted private key and certificate chain file for the SSL connection.

Changed in version 3.3: context was added.

Changed in version 3.3: source_address argument was added.

Changed in version 3.4: The class now supports hostname check with ssl.SSLContext.check_hostname and Server Name Indication (see ssl.HAS_SNI).

Deprecated since version 3.6: keyfile and certfile are deprecated in favor of context. Please use ssl.SSLContext.load_cert_chain() instead, or let ssl.create_default_context() select the system’s trusted CA certificates for you.

Changed in version 3.9: If the timeout parameter is set to be zero, it will raise a ValueError to prevent the creation of a non-blocking socket

You need to check that SSLV3 is enabled at Server end or not. Check out this link to see which client version can connect to which server version SSL Version Compatibility first.

import smtplib
import ssl
context = ssl.SSLContext(ssl.PROTOCOL_TLS) 
#Above line is required to switch default SSLV3 protocol to TLS, recommended by python docs
# If you want to use SSLV3 and you are sure that it is enabled on server end then use 
#context = ssl.SSLContext(ssl.PROTOCOL_SSLv3)
connection = smtplib.SMTP('smtp-mail.outlook.com', 587)
connection.ehlo()
connection.starttls(context=context)
connection.ehlo()
connection.login('[email protected]', 'otherwise_SMTPServerDisconnect')

1 Comment

I modified my answer. I removed the SSLContext piece and changed my password to one that didn't contain a new line character. I was able to send an email correctly with no errors.
1

The accepted answer didn't work for me, I kept getting this error:

smtplib.SMTPNotSupportedError: STARTTLS extension not supported by server.

I also tried SMTP_SSL instead of SMTP:

context = ssl.SSLContext(ssl.PROTOCOL_TLS) 
with smtplib.SMTP_SSL('smtp-mail.outlook.com', 587, context=context) as server:
    server.ehlo()
    server.starttls(context=context)

but got this error:

[SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:1131)

Fortunately this post (thanks @dhruv-gami) helped me find my issue.

I found out that my hostname (using WSL on windows) is uppercase, but Outlook servers do not accept uppercase host names.

The solution is to just add a lowercase string in the ehlo commands:

with smtplib.SMTP('smtp.office365.com', 587) as server:
    server.ehlo('lowercase')
    server.starttls()
    server.ehlo('lowercase')
    server.login('your_login', "your_password", initial_response_ok=True) 

1 Comment

nice catch. it would give cryptic messages otherwise, involving "invalid hostname" and whatnot.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.