How to use Microsoft Online Exchange with python to send mail - python-3.x

I want to send an Email from my outlook account using Python. I used the below code running in an AWS EC2 instance to generate an email.
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
server = smtplib.SMTP('smtp.office365.com', 587)
server.starttls()
server.login("<outlook_mail_id>","<outlook_password>")
server.sendmail("<outlook_mail_id>", "<recipient_email_id> ", "Test Message")
server.quit()
But while running this I get the below error
Traceback (most recent call last):
File "smtp_office_365.py", line 12, in <module>
server.login("<outlook_email_id>","<outlook_pass>")
File "/usr/local/lib/python3.8/smtplib.py", line 734, in login
raise last_exception
File "/usr/local/lib/python3.8/smtplib.py", line 723, in login
(code, resp) = self.auth(
File "/usr/local/lib/python3.8/smtplib.py", line 646, in auth
raise SMTPAuthenticationError(code, resp)
smtplib.SMTPAuthenticationError: (535, b'5.7.3 Authentication unsuccessful [MN2PR15CA0001.namprd15.prod.outlook.com]')
I am able to login into web outlook account using these credentials. Hence to check further I connected with my Admin team and they said that Basic Authentication is disabled for this account and can't be enabled in any case. They suggested me to use modern Authentication method by using Microsoft Online Exchange.
On further exploration I found the below script to send the mail
from exchangelib import DELEGATE, IMPERSONATION, Account, Credentials, Configuration
credentials = Credentials('<outlook_mail_id>', '<outlook_password>')
account = Account('<outlook_mail_id>', credentials=credentials, autodiscover=True)
for item in account.inbox.all().order_by('-datetime_received')[:100]:
print(item.subject, item.sender, item.datetime_received)
But I get the below error while running the script
Traceback (most recent call last):
File "test_exchange.py", line 5, in <module>
account = Account('<outlook_email_id>', credentials=credentials, autodiscover=True)
File "/home/ec2-user/.local/lib/python3.8/site-packages/exchangelib/account.py", line 116, in __init__
self.ad_response, self.protocol = discover(
File "/home/ec2-user/.local/lib/python3.8/site-packages/exchangelib/autodiscover/discovery.py", line 24, in discover
return Autodiscovery(
File "/home/ec2-user/.local/lib/python3.8/site-packages/exchangelib/autodiscover/discovery.py", line 123, in discover
ad_response = self._step_1(hostname=domain)
File "/home/ec2-user/.local/lib/python3.8/site-packages/exchangelib/autodiscover/discovery.py", line 433, in _step_1
return self._step_2(hostname=hostname)
File "/home/ec2-user/.local/lib/python3.8/site-packages/exchangelib/autodiscover/discovery.py", line 451, in _step_2
return self._step_3(hostname=hostname)
File "/home/ec2-user/.local/lib/python3.8/site-packages/exchangelib/autodiscover/discovery.py", line 483, in _step_3
return self._step_4(hostname=hostname)
File "/home/ec2-user/.local/lib/python3.8/site-packages/exchangelib/autodiscover/discovery.py", line 514, in _step_4
return self._step_6()
File "/home/ec2-user/.local/lib/python3.8/site-packages/exchangelib/autodiscover/discovery.py", line 572, in _step_6
raise AutoDiscoverFailed(
exchangelib.errors.AutoDiscoverFailed: All steps in the autodiscover protocol failed for email '<outlook_email_id>'. If you think this is an error, consider doing an official test at https://testconnectivity.microsoft.com
Please let me know if more details are required. Any help would be appreciated.
Thanks

Related

Winrs works while pywinrm module returns "the specified credentials were rejected by the server" error

I have a setup where I can winrs to the remote machine successfully without issues. However when I use pywinrm, I get an error about credentials.
Here is the authentication details of the remote windows the machine.
How one would go debugging this issue?
winrm get winrm/config/service/auth
Auth
Basic = false [Source="GPO"]
Kerberos = true [Source="GPO"]
Negotiate = false [Source="GPO"]
Certificate = false
CredSSP = false [Source="GPO"]
CbtHardeningLevel = Strict [Source="GPO"]
I tried this both from windows and linux and I get the same result. From the windows machine I can do winrs without issues.
Windows output:
import winrm
sess = winrm.Session('<hostname>', auth=('MOzsoy', '***'), transport='kerberos')
sess.run_cmd('hostname')
Traceback (most recent call last):
File "C:\Users\mozsoy\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\winrm\transport.py", line 328, in _send_message_request
response.raise_for_status()
File "C:\Users\mozsoy\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\requests\models.py", line 1021, in raise_for_status
raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 401 Client Error: for url: http://<hostname>:5985/wsman
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Users\mozsoy\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\winrm\__init__.py", line 40, in run_cmd
shell_id = self.protocol.open_shell()
File "C:\Users\mozsoy\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\winrm\protocol.py", line 166, in open_shell
res = self.send_message(xmltodict.unparse(req))
File "C:\Users\mozsoy\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\winrm\protocol.py", line 243, in send_message
resp = self.transport.send_message(message)
File "C:\Users\mozsoy\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\winrm\transport.py", line 322, in send_message
response = self._send_message_request(prepared_request, message)
File "C:\Users\mozsoy\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\winrm\transport.py", line 332, in _send_message_request
raise InvalidCredentialsError("the specified credentials were rejected by the server")
winrm.exceptions.InvalidCredentialsError: the specified credentials were rejected by the server
Linux output:
import winrm
sess = winrm.Session('<hostname>', auth=('MOzsoy', '***'), transport='kerberos')
sess.run_cmd("hostname")
/home/mozsoy/.local/lib/python3.7/site-packages/winrm/vendor/requests_kerberos/kerberos_.py:176: NoCertificateRetrievedWarning: Requests is running with a non urllib3 backend, cannot retrieve server certificate for CBT
NoCertificateRetrievedWarning)
Traceback (most recent call last):
File "/home/mozsoy/.local/lib/python3.7/site-packages/winrm/transport.py", line 328, in _send_message_request
response.raise_for_status()
File "/usr/lib/python3/dist-packages/requests/models.py", line 840, in raise_for_status
raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 401 Client Error: for url: http://<hostname>:5985/wsman
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/mozsoy/.local/lib/python3.7/site-packages/winrm/__init__.py", line 40, in run_cmd
shell_id = self.protocol.open_shell()
File "/home/mozsoy/.local/lib/python3.7/site-packages/winrm/protocol.py", line 166, in open_shell
res = self.send_message(xmltodict.unparse(req))
File "/home/mozsoy/.local/lib/python3.7/site-packages/winrm/protocol.py", line 243, in send_message
resp = self.transport.send_message(message)
File "/home/mozsoy/.local/lib/python3.7/site-packages/winrm/transport.py", line 309, in send_message
self.build_session()
File "/home/mozsoy/.local/lib/python3.7/site-packages/winrm/transport.py", line 292, in build_session
self.setup_encryption()
File "/home/mozsoy/.local/lib/python3.7/site-packages/winrm/transport.py", line 298, in setup_encryption
self._send_message_request(prepared_request, '')
File "/home/mozsoy/.local/lib/python3.7/site-packages/winrm/transport.py", line 332, in _send_message_request
raise InvalidCredentialsError("the specified credentials were rejected by the server")
winrm.exceptions.InvalidCredentialsError: the specified credentials were rejected by the server
It seems that pywinrm doesn't like this setting:
CbtHardeningLevel = Strict [Source="GPO"]
As it is configured through GPO, you probably need to contact your admin about this.
From what I found so far, pywinrm can't handle "Strict", but you need to use "Relaxed"
I encounterd this for Ansible, but I guess it's due to pywinrm.
https://github.com/diyan/pywinrm/issues/109
https://docs.ansible.com/ansible/latest/user_guide/windows_setup.html#http-401-credentials-rejected

How to run Python scripts on Azure?

I am trying to run some Python code in Azure, for the first time ever. I Googled 'how to run Python scripts in Azure' and came across the following link.
https://learn.microsoft.com/en-us/azure/automation/learn/automation-tutorial-runbook-textual-python-3
Essentially, I need to do this.
Open the textual editor by selecting Edit on the MyFirstRunbook-Python3 pane.
Add the following code to authenticate to Azure:
import os
from azure.mgmt.compute import ComputeManagementClient
import azure.mgmt.resource
import automationassets
def get_automation_runas_credential(runas_connection):
from OpenSSL import crypto
import binascii
from msrestazure import azure_active_directory
import adal
# Get the Azure Automation RunAs service principal certificate
cert = automationassets.get_automation_certificate("AzureRunAsCertificate")
pks12_cert = crypto.load_pkcs12(cert)
pem_pkey = crypto.dump_privatekey(crypto.FILETYPE_PEM,pks12_cert.get_privatekey())
# Get run as connection information for the Azure Automation service principal
application_id = runas_connection["ApplicationId"]
thumbprint = runas_connection["CertificateThumbprint"]
tenant_id = runas_connection["TenantId"]
# Authenticate with service principal certificate
resource ="https://management.core.windows.net/"
authority_url = ("https://login.microsoftonline.com/"+tenant_id)
context = adal.AuthenticationContext(authority_url)
return azure_active_directory.AdalAuthentication(
lambda: context.acquire_token_with_client_certificate(
resource,
application_id,
pem_pkey,
thumbprint)
)
# Authenticate to Azure using the Azure Automation RunAs service principal
runas_connection = automationassets.get_automation_connection("AzureRunAsConnection")
azure_credential = get_automation_runas_credential(runas_connection)
When I run that code, I get this error.
Failed
Traceback (most recent call last): File "C:\WPy64-3800\python-3.8.0.amd64\lib\automationassets.py", line 155, in _issue_request response = urllib.request.urlopen(request) File "C:\WPy64-3800\python-3.8.0.amd64\lib\urllib\request.py", line 222, in urlopen return opener.open(url, data, timeout) File "C:\WPy64-3800\python-3.8.0.amd64\lib\urllib\request.py", line 531, in open response = meth(req, response) File "C:\WPy64-3800\python-3.8.0.amd64\lib\urllib\request.py", line 640, in http_response response = self.parent.error( File "C:\WPy64-3800\python-3.8.0.amd64\lib\urllib\request.py", line 569, in error return self._call_chain(*args) File "C:\WPy64-3800\python-3.8.0.amd64\lib\urllib\request.py", line 502, in _call_chain result = func(*args) File "C:\WPy64-3800\python-3.8.0.amd64\lib\urllib\request.py", line 649, in http_error_default raise HTTPError(req.full_url, code, msg, hdrs, fp)urllib.error.HTTPError: HTTP Error 404: Not FoundDuring handling of the above exception, another exception occurred:Traceback (most recent call last): File "C:\Temp\nmcijfgi.bro\a761c289-67d9-493a-99b2-3ba7d46a7cd9", line 36, in <module> runas_connection = automationassets.get_automation_connection("AzureRunAsConnection") File "C:\WPy64-3800\python-3.8.0.amd64\lib\automationassets.py", line 232, in get_automation_connection connection = _client.get_connection_asset(name) File "C:\WPy64-3800\python-3.8.0.amd64\lib\automationassets.py", line 187, in get_connection_asset return self._issue_request(url, method=self._GET) File "C:\WPy64-3800\python-3.8.0.amd64\lib\automationassets.py", line 158, in _issue_request raise AutomationAssetNotFound()automationassets.AutomationAssetNotFound
Do I need 'cert', 'pks12_cert', or 'pem_pkey'? I don't think I have those. I'm not even sure what those things are. Again, I am trying to setup my Azure environment to run a Python script, which works totally fine on my desktop (Spyder).
Most likely you haven't created an Azure Run As Account. Follow the steps here to do so.

python sendemail script expecting authenication

I trying send email via python script with my company email id or donotreply#company.com.
Scripting throwing error you must authenticate.
python3 sendemail.py
Traceback (most recent call last):
File "sendemail.py", line 99, in <module>
sendemail(from_addr, to_addr_list, subject, cc_addr_list, message,
smtpserver="mail.company.net")
File "sendemail.py", line 73, in sendemail
problems = server.sendmail(from_addr, to_addr_list, message)
File "/usr/lib/python3.6/smtplib.py", line 867, in sendmail
raise SMTPSenderRefused(code, resp, from_addr)
smtplib.SMTPSenderRefused: (503, b'you must authenticate first
(#5.5.1)', 'user#company.com')
Please suggest what exactly issue happening same step in jenkins test email works.

exchangelib KeyError: 'contacts' or KeyError: 'inbox' or

I want to search in contact list of some account and get that contacts details back, but none of folders that told here not work because of KeyError exception .
Somehow i can't access to any of exchange account folders.
Is it permission or ... ?
Code :
from exchangelib import Credentials, Account, Configuration
from exchangelib.protocol import NoVerifyHTTPAdapter, BaseProtocol
BaseProtocol.HTTP_ADAPTER_CLS = NoVerifyHTTPAdapter
credentials = Credentials("YYY#XXX.com", 'PASSWORD')
account = Account(
primary_smtp_address="Account#XXX.com",
autodiscover=True,
credentials=credentials
)
print(account) # work properly with printing my account
print(account.contacts) # not work with KeyError Exception
Error :
Warning (from warnings module):
File "C:\Python\lib\site-packages\urllib3\connectionpool.py", line 857
InsecureRequestWarning)
InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings
Traceback (most recent call last):
File "C:\Python\lib\site-packages\cached_property.py", line 69, in __get__
return obj_dict[name]
KeyError: 'contacts'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Users\dvp7\Desktop\ex.py", line 20, in <module>
print(account.contacts)
File "C:\Python\lib\site-packages\cached_property.py", line 73, in __get__
return obj_dict.setdefault(name, self.func(obj))
File "C:\Python\lib\site-packages\exchangelib\account.py", line 169, in contacts
return self.root.get_default_folder(Contacts)
File "C:\Python\lib\site-packages\exchangelib\folders.py", line 965, in get_default_folder
for f in self._folders_map.values():
File "C:\Python\lib\site-packages\exchangelib\folders.py", line 928, in _folders_map
for f in FolderCollection(account=self.account, folders=distinguished_folders).get_folders():
File "C:\Python\lib\site-packages\exchangelib\services.py", line 1053, in call
shape=shape,
File "C:\Python\lib\site-packages\exchangelib\services.py", line 88, in _get_elements
response = self._get_response_xml(payload=payload)
File "C:\Python\lib\site-packages\exchangelib\services.py", line 189, in _get_response_xml
raise rme
File "C:\Python\lib\site-packages\exchangelib\services.py", line 171, in _get_response_xml
res = self._get_soap_payload(soap_response=soap_response_payload)
File "C:\Python\lib\site-packages\exchangelib\services.py", line 227, in _get_soap_payload
cls._raise_soap_errors(fault=fault) # Will throw SOAPError or custom EWS error
File "C:\Python\lib\site-packages\exchangelib\services.py", line 261, in _raise_soap_errors
raise vars(errors)[code](msg)
exchangelib.errors.ErrorInternalServerError: An internal server error occurred. The operation failed.
Build version :
Build=15.0.847.31, API=Exchange2013_SP1, Fullname=Microsoft Exchange Server 2013 SP1
This method is work :
account.root.walk() # output : <exchangelib.folders.FolderCollection object at 0x03ADCA90>
But when i append filter to it above error occurred.
KeyError: 'folders'
only root folder is works fine and there is nothing in it !
print(account.root.all()) # QuerySet(q=Q(), folders=[Root (root)])
For the record, this turned out to be a misbehaving archive inbox folder. Workaround provided in https://github.com/ecederstrand/exchangelib/issues/431#issuecomment-409832287 by telling exchangelib to ignore this folder:
from exchangelib.folders import ArchiveInbox
from exchangelib.version import EXCHANGE_2016
# Set to something newer than your current version
ArchiveInbox.supported_from = EXCHANGE_2016
For those who find this issue by searching for:
exchangelib KeyError: 'inbox'
the fix for us was to upgrade past 1.11.4. The was necessary after 9:15 am PST today

Tornado HTTPS Package Error

I have a simple example of a Python (3.6) Tornado (4.5.2) server and I am attempting to add ssl certs for testing. I have determined it is finding the key and csr files. Here is what my code looks like with a stack trace following detailing the error. Has anyone run into this or solved it?
import tornado.httpserver
import tornado.ioloop
import tornado.web
class indexHandler(tornado.web.RequestHandler):
def get(self):
self.write("hello")
application = tornado.web.Application([
(r'/', indexHandler),
])
if __name__ == '__main__':
http_server = tornado.httpserver.HTTPServer(application, ssl_options={
"certfile": "cert/ig.csr",
"keyfile": "cert/ig.key",
})
http_server.listen(443)
tornado.ioloop.IOLoop.instance().start()
Running on Python 3.6.4 and the server runs but when the page is accessed as https://localhost, it throws the following exception. What am I missing?
ERROR:asyncio:Exception in callback BaseAsyncIOLoop._handle_events(5, 1)
handle: <Handle BaseAsyncIOLoop._handle_events(5, 1)>
Traceback (most recent call last):
File "/<python path>/asyncio/events.py", line 145, in _run
self._callback(*self._args)
File "/<python path>/site-packages/tornado/platform/asyncio.py", line 102, in _handle_events
handler_func(fileobj, events)
File "/<python path>/site-packages/tornado/stack_context.py", line 276, in null_wrapper
return fn(*args, **kwargs)
File "/<python path>/site-packages/tornado/netutil.py", line 252, in accept_handler
callback(connection, address)
File "/<python path>/site-packages/tornado/tcpserver.py", line 264, in _handle_connection
do_handshake_on_connect=False)
File "/<python path>/site-packages/tornado/netutil.py", line 551, in ssl_wrap_socket
context = ssl_options_to_context(ssl_options)
File "/<python path>/site-packages/tornado/netutil.py", line 526, in ssl_options_to_context
context.load_cert_chain(ssl_options['certfile'], ssl_options.get('keyfile', None))
ssl.SSLError: [SSL] PEM lib (_ssl.c:3337)
In above error message, /<python path>/ is equal to:
"/usr/local/Cellar/python3/3.6.4_2/Frameworks/Python.framework/Versions/3.6/lib/python3.6/"
Its because the signature of the you certificate and the key doesn't match.
OK - I found it!! There are several online resources for determining if your certificate file and key match. I used THIS and they did not match. A quick call to Comodo (cert was thru Namecheap and then thru them) and they fixed it.
Lesson: Validate the key and certificate first!

Resources