Python SMTP 'unable to get local issuer certificate' in python virtualenv - python

Sorry if title is unclear.
I'm trying to send an email through python 3.10 through the standard library. It works locally on my machine with these default settings.
smtp_server = "smtp.office365.com"
port = 587 # For starttls
sender_email = os.environ.get("EMAIL")
password = os.environ.get("EMAIL_PASSWORD")
# Create a secure SSL context
context = ssl.create_default_context()
server = smtplib.SMTP(smtp_server,port)
try:
server.starttls(context=context) # Secure the connection
server.login(sender_email, password)
except Exception as e:
print(e)
However when I run this code manually from my company's server, I get a "unable to get local issuer certificate" error.
I've been able to remedy the issue by setting the ssl context to unverified:
context = ssl._create_unverified_context() # was ssl.create_default_context()
And this works when running the python file manually. However, this needs to run as a cronjob, and when the crontab runs the script with this 'fix' I get a different error.
Authentication unsuccessful, the user credentials were incorrect.
Which is ridiculous, because the same credentials worked with a different ssl context.
I'm using pythons virtualenv to run the script. I don't know any networking or certificate specific things to the company ubuntu server, but there's clearly something up. I just don't know what specifically.
Yes, I have looked through the multitude of similar questions, though none of them seem to quite fit this set of circumstances to help me.
Thanks in advance.

You are seeing two separate issues. TLS/certificate issues, and then an authentication issue which most likely has nothing to do with TLS.
There is no need for you to use unverified TLS. You can get the catrust from mozilla via the certifi package. Not sure if microsoft uses browser trust to sign their certificates.
>>> import certifi, ssl
>>> context = ssl.create_default_context()
>>> context.load_verify_locations(certifi.where())
That being said, a common mistake people make is assuming that cron jobs will load the same shell profile files that a login does. I would add error checking/debug loggin to make sure EMAIL_PASSWORD and EMAIL are set according to your expectations, since the error message is most likely coming from server.login line which has nothing to do with TLS.

Related

Send email in Python [duplicate]

This question already has answers here:
How to send an email with Gmail as provider using Python?
(16 answers)
Closed last month.
Now, as the Lesser secure apps feature in Gmail has been disabled, I am trying to find alternatives for email sending. I am trying freemail.hu as an alternative which supports SMTP protocol, but any other suggestion is highly welcome.
According to the web page, the data for SMTP are the following:
Server name: smtp.freemail.hu
Port: 587 (with STARTTLS)
Username: email address
Password: the same as used on the web
My code looks like this:
import smtplib
import ssl
try:
server = smtplib.SMTP('smtp.freemail.hu', 587)
server.starttls(context=ssl.create_default_context())
server.login('[myuser]#freemail.hu', '[mypassword]')
server.sendmail('[myuser]#freemail.hu', ['[myprivatemail]#gmail.com'], 'Test mail.')
except Exception as e:
print(e)
finally:
server.quit()
The username is password is correct: I checked them several times + it works on the web interface. However, I am getting the following error message:
(535, b'5.7.8 Error: authentication failed: [encoded value]')
Does anyone has an idea what the problem could be?
I tried two email providers (freemail.hu, mail.com), tried to log in with and without server name, tried to enter the password from command prompt, checked the settings looking for the feature similar to Lesser secure apps in Google, but nothing helped.
For Gmail the App Passwords as described on page https://support.google.com/mail/answer/185833 works well. The 2 step verification should be turned on, and then a 16 character long random password can be generated on the App passwords section.
Every tried ofunctions.mail package ?
Deals with ssl and tls, attachments, encoding, etc.
Install with pip install ofunctions.mailer
Usage
from ofunctions.mailer import Mailer
recipients = ['me#example.com', 'them#example.com', 'anyone#example.com', 'malformed_address_at_example.com']
mailer = Mailer(smtp_server='mail.example.com', smtp_port=465, security='ssl', debug=True, verify_certificates=False)
# split_mails=True will send one email per recipient
# split_mails=False will send one email for all recipients, which will be limited to the number of recipients the destination SMTP server allows
mailer.send_email(subject='test', sender_mail='me#example.com', recipient_mails=recipients, body='some body just told me', split_mails=True)
Just replace ssl with tls or None if needed.
See more usecases at github
disclaimer: I'm the author of ofunctions package.

smtplib.SMTPNotSupportedError: SMTP AUTH extension not supported by server. Python

I am attempting to run a python script to automate sending emails but I keep running into this error.
Any suggestions on how to fix this?
import smtplib
from email import message
from_addr = 'myemail#gmail.com'
to_addr = 'myemail#gmail.com'
subject = 'Test Email'
body = 'Test'
msg = message.Message()
msg.add_header('from', from_addr)
msg.add_header('to', to_addr)
msg.add_header('subject', subject)
msg.set_payload(body)
server = smtplib.SMTP('smtp.gmail.com', 587)
server.login(from_addr, 'password')
The error:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Program `Files\WindowsApps\PythonSoftwareFoundation.Python.3.10_3.10.1264.0_x64__qbz5n2kfra8p0\lib\smtplib.py", line 716, in login`
raise SMTPNotSupportedError(
smtplib.SMTPNotSupportedError: SMTP AUTH extension not supported by server.
I'm not shure, but for gmail you need https://myaccount.google.com/lesssecureapps Allow less secure apps: ON setting.
Or you need Google APIs for authentication: https://developers.google.com/gmail/api/quickstart/python
I was having the same issue. Google recent ended support for "allow less secure apps" and the commonly recommended answer of using an app password also does not appear to work reliably either (it will work sometimes, but then gmail will start rejecting the authentication a day or two later).
Google's suggested quickstart guide (https://developers.google.com/gmail/api/guides/sending) is incomplete but does eventually work. In that process, you will get an error because you did not redirect the URI. You'll need to add this to the approved URIs within your google API console and then follow the link again.
You will hit a 2nd issue because your user will not be approved to use your own project. You will need to add your gmail account as a test user.
Once you have the URI forwarding correctly and you are approved to use your own app, you will then get an error (HTTP Error 403) because the Gmail API will not be activated. Go back to the google API console and enable the Gmail API. Finally, you can run the quickstart.py file again and it will complete without errors.
I have not yet tested this solution for actually sending email, but it does appear to grant your app full access to the email account that you set up. I also do not know if this is a long term solution or if there are tokens which will time out.
Based on the difficulty of this, it seems that finding another email SMTP service may be a better solution if that's possible for your situation.
You can get your app password to login your account via smtp. This solves the issue for less secure app feature.
Coming towards your error it might be due to something is not supported but here I see you have not started TLS connection. Starting TLS connection can solve this error if there's no other issue.
server = smtplib.SMTP('smtp.gmail.com', 587)
server.starttls()
server.login(from_addr, 'password') # here you can need to use app password
This should solve the error most of the time if other things are correct.

Flask-Mail on Google App Engine Flexible ENV

I'm trying to get Flask-Mail setup on in Flexible ENV on Google App Engine. Flask-Mail works on my localhost using the credentials for a domain I am trying to use to send the mail. However, when using it on GAE through my API it returns a 502 error, however it shows no error messages in the logs or console. Going through the documentation for GAE Flexible it doesn't mention anything about NOT being able to use it, however it doesn't show how one would setup Flask-Mail either.
I have this..
mail = Mail()
print('1') // We Get here
msg = Message("Hello",
sender="me#mydomain.com",
recipients=["me#mydomain.com"])
print('2') // We get here
msg.body = 'Testing'
print('3') // We get here
mail.send(msg)
print('4') // This never gets call because I timeout on a 502 before this
I can tell I am not getting any fatal errors because the app stays working. However this fails with the 502. I have tried adding my email to the list of authorized senders but it doesn't seem to have helped.
I would appreciate any feedback. If I forced to use a 3rd party service to send mail it may cause me to move the project off of GAE.
As Ivan posted on his comment, to send email from a GAE app you need to use a mail service. Right now there are 3 options for apps on a flexible environment: Mailgun, MailJet and SendGrid. Choose the one you see better for your app.
After setting up an account on the mail service you have chosen, you have to prepare your code by integrating the parts related to the mail service.
These tutorials should help you establish the mail service for your app:
Mailgun
MailJet
SendGrid
I've had the same error but on a virtual machine on the internet ( linode service ) and it turned out that it has some thing to do with rDNS and some domain name config that you have to set up for your Ip address to get things working correctly , check this
https://www.linode.com/community/questions/19082/i-just-created-my-first-linode-and-i-cant-send-emails-why

401 Client Error: Unauthorized for url

Recently I started to get
requests.exceptions.HTTPError: 401 Client Error: Unauthorized for url: https://api.soundcloud.com/oauth2/token
using soundcloud (0.5.0) Python library.
It happens in
client = soundcloud.Client(client_id='id',
client_secret='secret',
username='user#mail.com',
password='passwd')
I double checked my credentials to make sure they are not the cause. I tried to get a Client instance from different IPs and different machines. At some random times during a day I can get a Client instance, but 99.99% of the day I get the error.
Does the error mean I was banned for some reason?
It may be helpful, I solved a similar problem by reading the username and password from the configuration file.
Try:
# config.ini
[my_app]
CLIENT_ID = enter_your_id
CLIENT_SECRET = enter_your_secret
USERNAME = enter_username
PASSWORD = enter_password
Install configparser from Python 3.8 for Python 2.6+: pip install configparser.
See the great documentation for more details.
import configparser
config = configparser.RawConfigParser()
config.read('config.ini')
my_id = config.get('my_app', 'CLIENT_ID')
my_secret = config.get('my_app', 'CLIENT_SECRET')
my_user = config.get('my_app', 'USERNAME')
my_pass = config.get('my_app', 'PASSWORD')
client = soundcloud.Client(client_id=my_id,
client_secret=my_secret,
username=my_user,
password=my_pass)
Probably you are using a third-party app to access your account,
in case you are using Gmail service for your purpose, consider allowing third-party apps to have access to your Gmail account, how are you going to do that:
Go to https://myaccount.google.com/security
Use Two-Step-Authentication and enable it.
Create an App Password, Select App > Mail | Select Device > Windows Computer.
And use the password given
And that should solve your issue.

Python login to email server authentication error

I am on a Linux machine. My company has an email exchange server which is already configured. I am using a Python script to try to login to the email server so that I can send an email programmatically. Here is what I have so far -
server = smtplib.SMTP('email-0.abc.com', 25)
server.set_debuglevel(1)
server.ehlo_or_helo_if_needed()
server.login('abc/johndoe', 'pwd')
However, at the server.login command, I get an error as
raise SMTPException("No suitable authentication method found.")
SMTPException: No suitable authentication method found.
Anyone know what the problem is please?
Thanks
You might need to switch to STARTTLS authentication. Here's an example that helped me.
How To Send Email In Python Via SMTPLIB
It seems that your Mail Server is rejecting the plain Authentication method.
What server do you use?
If MS Exchange please see this article: http://www.exchangeinbox.com/article.aspx?i=93
I was getting the same error. My case could be the different from yours but error is same as you mentioned.
In my scenario, I don't have to pass the username and password for authentication as server IP was added in white-list of SMTP mail server. And I was passing username and password for authentication which was giving me the error stating "No suitable authentication method found."
This may not be the case with you but I just thought to share the my experience for the same kind of error so that anyone coming to this thread can benefit from it.
Thanks.
The Exchange server I was connecting to, required NTLM authentication, which is not supported by smtplib out of the box.
As of this writing (January 2022) and according to my modest research, the most maintained Python library that solves this problem, is pyspnego. The following snippet was provided by the library author and worked for me without any modifications:
import base64
import spnego
from smtplib import SMTPException, SMTPAuthenticationError
def ntlm_authenticate(smtp, username, password):
auth = spnego.client(username, password, service="SMTP", protocol="ntlm")
ntlm_negotiate = auth.step()
code, response = smtp.docmd("AUTH", "NTLM " + base64.b64encode(ntlm_negotiate).decode())
if code != 334:
raise SMTPException("Server did not respond as expected to NTLM negotiate message")
ntlm_challenge = base64.b64decode(response)
ntlm_auth = auth.step(ntlm_challenge)
code, response = smtp.docmd("", base64.b64encode(ntlm_auth).decode())
if code != 235:
raise SMTPAuthenticationError(code, response)

Categories