smtplib bug? starttls/quit fails when called the second time - python

Take this code
import smtplib
s = smtplib.SMTP()
s.set_debuglevel(1)
print "-------------------------------------------------------------------------"
s.connect("smtp.gmail.com",587)
s.starttls()
s.login("USERNAME","PASSWORD")
s.quit()
print "========================================================================="
s.connect("smtp.gmail.com",587)
s.starttls()
s.login("USERNAME","PASSWORD")
s.quit()
print "-------------------------------------------------------------------------"
first time it connects, it starts just fine....
second time it produces an exception about TLS as seen here...
Traceback (most recent call last):
File "mtest.py", line 12, in <module>
s.starttls()
File "/usr/lib/python2.7/smtplib.py", line 635, in starttls
raise SMTPException("STARTTLS extension not supported by server.")
smtplib.SMTPException: STARTTLS extension not supported by server.
Am I missing something stupid or is there a bug?
P.s. I wrote this test as I was getting the same problem in my other 'threaded' script, so wanted to make sure that it was nothing to do with threading.

I'm guessing that after the s.quit() the connection s is dead and cannot be used for anything else. If so, you'd need another s = smtplib.SMTP() for the second mail transfer.
The quit() documentation seems to suggest this is so:
Terminate the SMTP session and close the connection.

Related

Is it OK to connect smtp server once and send many emails in a long period?

here is the code from my college, but I thougt it's not much effecient 'cause it'll connect smtp server and login every time, and just send one mail..., so how about I connect smtp and login for the first time once the service started, and using this long connection to send mail aferwards?
def send_email(receiver, subject, mail_body):
msg = MIMEText(mail_body, _subtype='html', _charset='utf-8')
msg['Subject'] = Header(subject, 'utf-8')
msg['From'] = XXXX#xx.com
msg['To'] = receiver
try:
smtp = smtplib.SMTP()
smtp.connect(xxxx.com)
smtp.login(user, password)
smtp.sendmail(XXXX#xx.com, receiver.split(','), msg.as_string())
except Exception:
logger.error('Send email failed: %s' % traceback.format_exc())
finally:
smtp.quit()
It's OK to reuse the connection to send email, but the server may terminate the connection at any time, that depends on server's strategy. So just catch the corresponding error and reconnect again.
def send_email(receiver, subject, mail_body):
try:
smtp = smtplib.SMTP()
smtp.connect(xxxx.com)
smtp.login(user, password)
# for test
for i in range (10):
smtp.sendmail(XXXX#xx.com, receiver.split(','), msg.as_string())
except Exception:
logger.error('Send email failed: %s' % traceback.format_exc())
finally:
smtp.quit()
using the above code, I test sending 10 emails using the same connection, but got Exception below, I think that may be related to the safety strategy of target smtp server.
[2021-03-01 15:56:25,386] [ERROR] [125:MainThread] [send_email.py:47] [send_email]:send email failed: Traceback (most recent call last):
File "send_email.py", line 41, in send_email
smtp.sendmail(EmailAccount, email_receiver.split(','), msg.as_string())
File "/usr/lib/python2.7/smtplib.py", line 737, in sendmail
raise SMTPSenderRefused(code, resp, from_addr)
SMTPSenderRefused: (450, 'Requested mail action not taken: too much delivery in this connection', 'xxxx#xxxx.com')

Python smtplib second connection failing

I am trying to connect to my mail server, then disconnect, then reconnect at another time. The initial connection works and the email is sent. I disconnect using quit() and the reply is closing the connection. When I attempt to connect again, it raises SMTPServerDisconnected please run connect() first. I found this from a few years ago as the exact same problem (https://bugs.python.org/issue22216) and it shows that it was fixed. I am having this same issue now and unsure how to properly fix it or close the connection.
mail = smtplib.SMTP_SSL('mail.hostname.com', 465)
MAIL_PASS = 'password'
SENDER = 'name#hostname.com'
RECEIVER = 'receiver#something.com'
while True:
if (something)
mail.login(SENDER, MAIL_PASS)
mail.sendmail(SENDER, RECEIVER, 'test email')
mail.quit()
elif (something else)
mail.login(SENDER, MAIL_PASS)
mail.sendmail(SENDER, RECEIVER, 'test2 email')
mail.quit()
After the first email and the quit request it says this:
reply: b'221 box5454.bluehost.com closing connection\r\n'
reply: retcode (221); Msg: b'box5454.bluehost.com closing connection'
The next connection attempt says this:
send: 'ehlo [127.0.1.1]\r\n'
Traceback (most recent call last):
mail.login(SENDER, MAIL_PASS)
self.ehlo_or_helo_if_needed()
if not (200 <= self.ehlo()[0] <= 299):
self.putcmd(self.ehlo_msg, name or self.local_hostname)
self.send(str)
raise SMTPServerDisconnected('please run connect() first')
smtplib.SMTPServerDisconnected: please run connect() first
I have found a way to make the program work. I am using a while True to continue the program. It seems when I declare the variable for the smtplib before while True, it has the problem. I declare the variable after while True and it works. May be a noob problem using while True, but it drove me nuts and hopefully it will help someone else
MAIL_PASS = 'password'
SENDER = 'name#hostname.com'
RECEIVER = 'receiver#something.com'
while True:
mail = smtplib.SMTP_SSL('mail.hostname.com', 465)
if (something)
mail.login(SENDER, MAIL_PASS)
mail.sendmail(SENDER, RECEIVER, 'test email')
mail.quit()
elif (something else)
mail.login(SENDER, MAIL_PASS)
mail.sendmail(SENDER, RECEIVER, 'test2 email')
mail.quit()

Connection Error SMTP python

I've been using python for a bit now and have been using the email function without any errors in the past but on the latest program I have made I've been getting this error
Traceback (most recent call last):
File "daemon.py", line 62, in <module>
scraper.run()
File "c:\cfsresd\scraper.py", line 48, in run
self.scrape()
File "c:\cfsresd\scraper.py", line 44, in scrape
handler(msg)
File "daemon.py", line 57, in handler
server.ehlo()
File "C:\Python27\lib\smtplib.py", line 385, in ehlo
self.putcmd(self.ehlo_msg, name or self.local_hostname)
File "C:\Python27\lib\smtplib.py", line 318, in putcmd
self.send(str)
File "C:\Python27\lib\smtplib.py", line 310, in send
raise SMTPServerDisconnected('please run connect() first')
smtplib.SMTPServerDisconnected: please run connect() first
I used the same email code for all my projects but this is first time is done it. I've tried adding the connect() but that made no difference. Below is email section of my script
msg = MIMEText ('%s - %s' % (msg.text, msg.channel))
server = smtplib.SMTP('smtp.gmail.com:587')
server.ehlo()
server.starttls()
msg['Subject'] = "msg.channel"
msg['From'] = ('removed')
msg['To'] = ('removed')
server.login('user','password')
server.sendmail(msg.get('From'),msg["To"],msg.as_string())
server.close()
server.ehlo()
server.quit()
print 'sent'
cheers for any help
shaggy
all sorted took a few idea and tried the code below
msg = MIMEText ('%s - %s' % (msg.text, msg.channel))
server = smtplib.SMTP('smtp.gmail.com')
server.starttls()
server.login('user','pass')
msg['Subject'] = "msg.channel"
msg['From'] = ('from')
msg['To'] = ('to')
server.sendmail(msg.get('From'),msg["To"],msg.as_string())
server.quit()
So i removed ehlo(), close() and port number. now i have to workout how to change the subject to msg.channel so it changes each time.
thanks all
Try using SMTP's empty constructor, then call connect(host, port):
server = smtplib.SMTP()
server.connect('smtp.gmail.com', '587')
server.ehlo()
server.starttls()
server.login(username, password)
You have an ehlo after close. That seems unlikely to ever succeed. Also, quit does close so you can probably just get rid of the ehlo and close calls near the end
You can still have an encrypted connection with the smtp server by using the SMTP_SSL class without needing the starttls call (shorter). You don't need to be calling the ehlo every time, that's done automatically when needed, and when connecting to the default port, don't have to supply one when creating instances SMTP* classes.
msg = MIMEText ('%s - %s' % (msg.text, msg.channel))
msg['To'] = ','.join(receivers)
msg['Subject'] = 'msg.channel'
msg['From'] = 'someone#somedomain.com'
Using SMTP with the starttls:
server = smtplib.SMTP('smtp.gmail.com')
server.starttls()
server.login('user', 'password')
server.sendmail(msg['From'], receivers, msg.as_string())
and now with the SMTP_SSL class
server = smtplib.SMTP_SSL('smtp.gmail.com')
server.login('user', 'password')
server.sendmail(msg['From'], receivers, msg.as_string())
and finally
server.quit()
For Pyhton 3.6.*
Note : In gmail it will work only if 2-Step verification is turned off.
Allow gmail to open via low secured app.
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from_addr = 'sender-email-id'
to_addr = 'receiver-email-id'
text = 'Hi Friend!!!'
username = 'sender-username'
password = 'password'
msg = MIMEMultipart()
msg['From'] = from_addr
msg['To'] = to_addr
msg['Subject'] = 'Test Mail'
msg.attach(MIMEText(text))
server = smtplib.SMTP('smtp.gmail.com:587')
server.ehlo()
server.starttls()
server.ehlo()
server.login(username,password)
server.sendmail(from_addr,to_addr,msg.as_string())
server.quit()
I'm the maintainer of yagmail, a package that should make it really easy to send an email.
import yagmail
yag = yagmail.SMTP('user','password')
yag.send(to = 'to#gmail.com', subject = 'msg.channel')
when yag leaves scope, it will auto-close.
I would also advise you to register in keyring once, so you'll never have to write the password in a script. Just run once:
yagmail.register('user', 'password')
You can then shorten it to this:
SMTP().send('to#gmail.com', 'msg.channel')
You can install it with pip or pip3 (for Python 3). You can also read more about it, with functionality as easily adding attachments, inline images/html, aliases etc.
I had a similar problem when I tried to send an e-mail from Celery (as a Docker container). I added env_file to the worker and beat containers in a docker compose file.
env_file: ./env/dev/.env
In that file I have an e-mail configuration.
EMAIL_HOST=smtp.gmail.com
EMAIL_HOST_USER=your_mail
EMAIL_HOST_PASSWORD=your_password
EMAIL_PORT=587
I solved this error just by removing this line:
server.quit()
raise SMTPServerDisconnected('please run connect() first')
if you had this error you my be want install this :
pip install django-smtp-ssl
this one to install smtp library and ssl protocol
its work perfecly for me

Python sendmail error script

#!/usr/bin/python
import smtplib
sender = 'from#fromdomain.com'
receivers = ['to#todomain.com']
message = """From: From Person <from#fromdomain.com>
To: To Person <TEST#yahoo.com>
Subject: SMTP e-mail test
This is a test e-mail message.
"""
try:
smtpObj = smtplib.SMTP('localhost')
smtpObj.sendmail(sender, receivers, message)
print "Successfully sent email"
except SMTPException:
print "Error: unable to send email"
I keep getting the folllowing errors even though I imported everything. I'm using Linux, what's missing?
File "email.py", line 3, in <module>
import smtplib
File "/usr/lib/python2.7/smtplib.py", line 46, in <module>
import email.utils
File "/home/email.py", line 19, in <module>
except SMTPException:
The only obvious thing that should not work is that SMTPException needs to be smtplib.SMTPException (or import it for unqualified use with from smtplib import SMTPException).
Otherwise, after changing to my own (valid) addresses and my own SMTP server, your code works fine.

STARTTLS extension not supported by server

This maybe a repeated question but I'm still facing issues on this, hope there's a solution around. Thanks in advance.
I'm trying to send mail through the company's server
I'm currently using Python version 2.6 and Ubuntu 10.04
This is the error message I got
Traceback (most recent call last):
File "hxmass-mail-edit.py", line 227, in <module>
server.starttls()
File "/usr/lib/python2.6/smtplib.py", line 611, in starttls
raise SMTPException("STARTTLS extension not supported by server.") smtplib.SMTPException: STARTTLS extension not supported by server.
Here goes part of the code
server = smtplib.SMTP('smtp.abc.com', 587)
server.set_debuglevel(1)
server.ehlo()
server.starttls()
server.ehlo()
server.login('sales#abc.com', 'abc123')
addressbook=sys.argv[1]
Remove the ehlo() before starttls().
starttls() + ehlo() results in two HELLO messages, which cause the server remove the STARTTLS in the reply message.
server = smtplib.SMTP('smtp.abc.com', 587)
server.starttls()
server.ehlo()
server.login('sales#abc.com', 'abc123')
I had a similar issue trying to send a mail through the company's server (without autentication needed)
I solved removing the server.ehlo and removing the port number:
server = smtplib.SMTP("smtp.mycompany.com")
server.sendmail(fromaddr, toaddr, text)
removing server.ehlo() before server.starttls() helped me get my code working! Thank you, Leonard!
my code:
s = smtplib.SMTP("smtp.gmail.com",587)
s.starttls()
s.ehlo
try:
s.login(gmail_user, gmail_psw)
except SMTPAuthenticationError:
print 'SMTPAuthenticationError'
s.sendmail(gmail_user, to, msg.as_string())
s.quit()
The error says it all, it seems the SMTP server sou are using doesn't support STARTTLS and you aru issuing server.starttls(). Try using the server without calling server.starttls().
Without more info is the only I can say.
I am able to resolve the issue with below code, by adding port number with server name:
server = smtplib.SMTP('smtp.abc.com:587')
from smtplib import SMTP_SSL, SMTP, SMTPAuthenticationError
from ssl import create_default_context
from email.message import EmailMessage
sender = 'aaa#bbb.com'
description = "This is the test description supposed to be in body of the email."
msg = EmailMessage()
msg.set_content(description)
msg['Subject'] = 'This is a test title'
msg['From'] = f"Python SMTP <{sender}>"
msg['To'] = 'bbb#ccc.com'
def using_ssl():
try:
server = SMTP_SSL(host='smtp.gmail.com', port=465, context=create_default_context())
server.login(sender, password)
server.send_message(msg=msg)
server.quit()
server.close()
except SMTPAuthenticationError:
print('Login Failed')
def using_tls():
try:
server = SMTP(host='smtp.gmail.com', port=587)
server.starttls(context=create_default_context())
server.ehlo()
server.login(sender, password)
server.send_message(msg=msg)
server.quit()
server.close()
except SMTPAuthenticationError:
print('Login Failed')
By testing and researching myself, I found out that the gmail servers do not use tls connections with python anymore.
You must not use service.startttls(). Gmail service do not support this type of connection anymore.
Also remember to use the SMTP ports (mail reserved ports) for sending emails.
POP3 and IMAP ports for receiving email.
s_u = "Test"
service = smtplib.SMTP_SSL("smtp.gmail.com", 465)
service.ehlo()
service.sendmail("SENDER_EMAIL","RECEIVER_EMAIL","MESSAGE")
You can't send the email even if you put the correct credentials,
look at this: Login credentials not working with Gmail SMTP
Are you sure that you want to encrypt (StartTLS) the connection to the mail server? I would contact someone who knows the insides of that server to see what protocol/encryption to use.
You say that upon removing the call to server.starttls(), you get a different series of error messages. Could you please post those messages as well?
Also, you might want to read up on StartTLS so you understand what it is and why you would want to use it. It seems you're writing a Serious Business program, in which case you'll probably want to understand what you are doing, security-wise.
Yes putting server.starttls() above server.ehlo() solved this.

Categories

Resources