Python: smtplib.SMTPServerDisconnected: please run connect() first - python

I'm attempting to create a program that reads the unread emails and responds to the send with the usage of auto-reply which would be triggered by the use of certain phrases. I'm doing this in Mac OSX in Visual Code. I'm able to connect to IMAP and SMTP but then I get the following error,
smtplib.SMTPServerDisconnected: please run connect() first.
I tried to use an exception that was part of the smtplib which should be raised if the SMTP server disconnects, but it doesn't do anything.
def smtp_init():
print("Initializing STMP . . .",end = '')
global s
s = smtplib.SMTP(smtpserver,smtpserverport)
status_code = s.starttls()[0]
if status_code is not 220:
raise Exception('Starting tls failed: '+ str(status_code))
status_code = s.login(radr,pwd)[0]
if status_code is not 235:
raise Exception('SMTP login failed: '+ str(status_code))
print("Done. ")
except smtplib.SMTPServerDisconnected:
smtp_init()
continue
The expected results would be to have the program in a loop checking the emails and responding to them if they have a phrase that corresponds to the auto-reply.

Related

smtplib times out connecting to AWS SES despite receiving a 220 service ready

I am attempting to send an email with AWS SES using a Dockerized Python program. When I try to connect to SES by making an SMTP instance, the program hangs and times out.
To reproduce:
Start the Python 3.6.8 REPL
Import smtplib
>>> import smtplib
Try to connect to SES, and observe how the statement hangs.
>>> conn = smtplib.SMTP(host='email-smtp.us-west-2.amazonaws.com', port=25)
# terminal hangs for 10 seconds
Try using the connection, which fails.
>>> conn.noop()
(451, b'4.4.2 Timeout waiting for data from client.')
>>> conn.noop()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib64/python3.6/smtplib.py", line 514, in noop
return self.docmd("noop")
File "/usr/lib64/python3.6/smtplib.py", line 421, in docmd
return self.getreply()
File "/usr/lib64/python3.6/smtplib.py", line 394, in getreply
raise SMTPServerDisconnected("Connection unexpectedly closed")
smtplib.SMTPServerDisconnected: Connection unexpectedly closed
Unsurprisingly, step (3) sends a DNS query for the SES endpoint, and then connects; the SES endpoint responds with 220 service ready nearly instantaneously. No traffic is exchanged until 10 seconds later, when SES closes the connection with 451 timeout waiting for client. The statement completes, and then runs the rest of my program which, of course, doesn't work.
For context, the rest of my script is as follows:
smtp_host = 'email-smtp.us-west-2.amazonaws.com'
smtp_port = 25
smtp_proto = 'tls'
with smtplib.SMTP(host=smtp_host, port=smtp_port) as connection:
try:
ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23 if smtp_proto == 'ssl' else ssl.PROTOCOL_TLS)
connection.starttls(context=ctx)
connection.ehlo()
connection.login(smtp_user, smtp_pass)
connection.send_message(from_addr=sender, to_addrs=recipients, msg=message)
except smtplib.SMTPHeloError as e:
print(f"SMTP HELO Failed: {e}")
except smtplib.SMTPAuthenticationError as e:
print(f"SMTP AUTH Failed: {e}")
except smtplib.SMTPException as e:
print(f"Failed to send email: {e}")
I've attempted to connect on ports 25, 587, 2587, and 465. I've done the same with the SMTP_SSL object instead, as well as changing the context in the starttls call to various SSL / TLS versions (the SSL versions result in this error - but this isn't relevant since I can't get to this portion of the script, anyway).
I've tested my connection to SES according to this article. I've also tried parts of this and this SO post (as well as a myriad of others that are lost in my browser history).
To actually send emails, I need to connect a second time. Connecting, then waiting for a timeout, then connecting again, seems wrong. What is the proper way to do this?

How to determine if remote ESXI Host has booted fully?

I am writing a Python Script to fully boot up a handful of ESXI hosts remotely, and I am having trouble with determining when ESXI has finished booting and is ready to receive commands send over SSH. I am running the script on a windows host that is hardwired to each ESXI host and the system is air-gapped so there is no firewalls in the way and no security software would interfere.
Currently I am doing this: I remote into the chassis through SSH and send the power commands to the ESXI host - this works and has always worked. Then, I attempt to SSH into each blade and send the following command
esxcli system stats uptime get
The command doesn't matter, I just need a response to make sure that the host is up. Below is the function I am using to send the SSH commands in hopes of getting a response
def send_command(ip, port, timeout, retry_interval, cmd, user, password):
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
retry_interval = float(retry_interval)
timeout = int(timeout)
timeout_start = time.time()
worked = False
while worked == False:
time.sleep(retry_interval)
try:
ssh.connect(ip, port, user, password, timeout=5)
stdin,stdout,stderr=ssh.exec_command(cmd)
outlines=stdout.readlines()
resp=''.join(outlines)
print(resp)
worked = True
return (resp)
except socket_error as e:
worked = False
print(e)
continue
except paramiko.ssh_exception.SSHException as e:
worked = False
# socket is open, but not SSH service responded
print(e)
continue
except TimeoutError as e:
print(e)
worked = False
pass
except socket.timeout as e:
print(e)
worked = False
continue
except paramiko.ssh_exception.NoValidConnectionsError as e:
print(e)
worked = False
continue
except socket.error as serr:
print(serr)
worked = False
continue
except IOError as e:
print(e)
worked = False
continue
except:
print(e)
worked = False
continue
My goal here is to catch all of the exceptions long enough for the host to finish booting and then receive a response. The issue is that sometimes it will loop for several minutes (as expected when booting a system like this), and then it will print
IO error: [Errno 111] Connection refused
And then drop out of the function/try catch block and never establish the connection. I know that this is a fault of my exceptions handling because when this happens, I stop the script, wait a few minutes, run it again without touching anything else and the esxcli command will work perfectly and the script will work great.
How do I prevent the Errno 111 error from breaking my loop? Any help is greatly appreciated
Edit: One possible duct tape solution could be changing the command to "esxcli system hostname get" and checking the response for the word "Domain". This might work because the IOError seems to be a response and not an exception, I'll have to wait until monday to test that solution though.
I solved it. It occured to me that I was handling all possible exceptions that any python code could possibly throw, so my defect wasn't a python error and that would make sense why I wasn't finding anything online about the relationship between Python, SSH and the Errno 111 error.
The print out is in fact a response from the ESXI host, and my code is looking for any response. So I simply changed the esxcli command from requesting the uptime to
esxcli system hostname get
and then through this into the function
substring = "Domain"
if substring not in resp:
print(resp)
continue
I am looking for the word "Domain" because that must be there if that call is successful.
How I figure it out: I installed ESXI 7 on an old Intel Nuc, turned on SSH in the kickstart script, started the script and then turned on the nuc. The reason I used the NUC is because a fresh install on simple hardware boots up much faster and quietly than Dell Blades! Also, I wrapped the resp variable in a print(type(OBJECT)) line and was able to determine that it was infact a string and not an error object.
This may not help someone that has a legitimate Errno 111 error, I knew I was going to run into this error each and everytime I ran the code and I just needed to know how to handle it and hold the loop until I got the response I wanted.
Edit: I suppose it would be easier to just filter for the world "errno" and then continue the loop instead of using a different substring. That would handle all of my use cases and eliminate the need for a different function.

psycopg2.OperationalError: SSL SYSCALL error: EOF detected

I was using psycopg2 in python script to connect to Redshift database and occasionally I receive the error as below:
psycopg2.OperationalError: SSL SYSCALL error: EOF detected
This error only happened once awhile and 90% of the time the script worked.
I tried to put it into a try and except block to catch the error, but it seems like the catching didn't work. For example, I try to capture the error so that it will automatically send me an email if this happens. However, the email was not sent when error happened. Below are my code for try except:
try:
conn2 = psycopg2.connect(host="localhost", port = '5439',
database="testing", user="admin", password="admin")
except psycopg2.Error as e:
print ("Unable to connect!")
print (e.pgerror)
print (e.diag.message_detail)
# Call check_row_count function to check today's number of rows and send
mail to notify issue
print("Trigger send mail now")
import status_mail
print (status_mail.redshift_failed(YtdDate))
sys.exit(1)
else:
print("RedShift Database Connected")
cur2 = conn2.cursor()
rowcount = cur2.rowcount
Errors I received in my log:
Traceback (most recent call last):
File "/home/ec2-user/dradis/dradisetl-daily.py", line 579, in
load_from_redshift_to_s3()
File "/home/ec2-user/dradis/dradisetl-daily.py", line 106, in load_from_redshift_to_s3
delimiter as ','; """.format(YtdDate, s3location))
psycopg2.OperationalError: SSL SYSCALL error: EOF detected
So the question is, what causes this error and why isn't my try except block catching it?
From the docs:
exception psycopg2.OperationalError
Exception raised for errors that are related to the database’s
operation and not necessarily under the control of the programmer,
e.g. an unexpected disconnect occurs, the data source name is not
found, a transaction could not be processed, a memory allocation error
occurred during processing, etc.
This is an error which can be a result of many different things.
slow query
the process is running out of memory
other queries running causing tables to be locked indefinitely
running out of disk space
firewall
(You should definitely provide more information about these factors and more code.)
You were connected successfully but the OperationalError happened later.
Try to handle these disconnects in your script:
Put the command you want to execute into a try-catch block and try to reconnect if the connection is lost.
Recently encountered this error. The cause in my case was the network instability while working with database. If network will became down for enough time that the socket detect the timeout you will see this error. If down time is not so long you wont see any errors.
You may control timeouts of Keepalive and RTO features using this code sample
s = socket.fromfd(conn.fileno(), socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
s.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 6)
s.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 2)
s.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 2)
s.setsockopt(socket.IPPROTO_TCP, socket.TCP_USER_TIMEOUT, 10000)
More information you can find in this post
If you attach the actual code that you are trying to except it would be helpful. In your attached stack trace its : " File "/home/ec2-user/dradis/dradisetl-daily.py", line 106"
Similar except code works fine for me. mind you, e.pgerror will be empty if the error occurred on the client side, such as the error in my example. the e.diag object will also be useless in this case.
try:
conn = psycopg2.connect('')
except psycopg2.Error as e:
print('Unable to connect!\n{0}'.format(e))
else:
print('Connected!')
Maybe it will be helpful for someone but I had such an error when I've tried to restore backup to the database which has not sufficient space for it.

Fail early if JIRA credentials are incorrect

I am connecting to JIRA using the jira python package:
def connect_to_JIRA():
'''
Generic function to get JIRA connection
'''
if settings.JIRA_AVAILABLE:
try:
jira_conn = JIRA(
basic_auth=(settings.JIRA_USER, settings.JIRA_PASSWORD),
server=settings.JIRA_SERVER
)
return jira_conn
except Exception as e:
log.error("Unexpected problem connecting to JIRA")
raise
else:
log.error("JIRA credentials not configured or incomplete")
raise
Which works fine, but if the credentials are incorrect (not missing) then it goes through a 1-2 minute long song and dance:
WARNING:root:Got recoverable error from GET [my jira server address], will retry [1/3] in 1.7998166159998785s. Err: 401 Unauthorized
WARNING:root:Got recoverable error from GET [my jira server address], will retry [2/3] in 39.04052373359595s. Err: 401 Unauthorized
WARNING:root:Got recoverable error from GET [my jira server address], will retry [3/3] in 46.35106211454652s. Err: 401 Unauthorized
before finally triggering my except clause. Is there any way to make it "fail fast"?
Set max_retries to 1. Current default is 3.
jira_conn = JIRA(
basic_auth=(settings.JIRA_USER, settings.JIRA_PASSWORD),
server=settings.JIRA_SERVER,
max_retries=1
)

Send mails with Python and an IMAP/SMTP Server

i have a couple issues with sending Email with Python using my own SMTP/IMAP Server.
Here's the code :
import sys
import imaplib
import smtplib
import email
import email.header
import datetime
smtp_session = smtplib.SMTP(mail_server)
try:
smtp_session.ehlo()
except :
err = sys.exc_info()[0]
message = """\
From: %s
To: %s
Subject: %s
%s""" % (email_from, ", ".join([email_to]), "subject", "body")
try:
smtp_session.sendmail(email_from, [email_to], message)
smtp_session.quit()
except:
err = sys.exc_info()[0]
if err != "" or err !=None:
NagiosCode = 2
NagiosMsg = "CRITICAL: Script execution failed : " + str(err)
Ok so for the two issues i have:
When i send a mail from my script i need the mail to appear in the "sent items" diretory of my mail box who send it.
Second issue i have : When sending my mail i catch this exception :
<class 'smtplib.SMTPException'>
EDIT : Exception trace :
File "checkIMAP_client.py", line 153, in <module>
smtp_session.login(login, password)
File "/usr/lib64/python2.6/smtplib.py", line 559, in login
raise SMTPException("SMTP AUTH extension not supported by server.")
smtplib.SMTPException: SMTP AUTH extension not supported by server.
EDIT :
It seems my SMTP server doesn't require authentification.
But the program still returns me an empty exception.
Code is updated.
So for the two issues i had, i found the answers thanks to the above comments :
Putting my sent e-mail via SMTP in the right mailbox in the Sent directory :
https://pymotw.com/2/imaplib/
Look for "Uploading messages"
Exception issue :
I had no auth methods set on my SMTP server.

Categories

Resources