how to catch error in finally block in python - python

I could see several topics on try - catch but doesnt seem to discuss errors if any from finally block itself. I found that the error is not handled if it is in finally block. What would be the ideal way to manage finally?
For eg. below is a mail function. if there is any error in try block, finally will execute the quit method which itself is not initiated so an unhandled error occurs. So is it better to ensure there is no errors occur in finally block?
def send_email(ldap, email_address, password, msg):
try:
message = MIMEMultipart('alternative')
message['To'] = email.utils.formataddr(('Recipient', '%s#abc.com'%email_address))
message['From'] = email.utils.formataddr(('Author', '%s#abc.com'%email_address))
message['Subject'] = 'Sample subject'
text = "%s"%msg
html = MIMEText('<html><head></head><h2>data</h2><body><p>%s</p></body></html>'%msg,'html')
message.attach(html)
server = smtplib.SMTP(host="ip",port=0)
server.set_debuglevel(True)
# identify ourselves, prompting server for supported features
server.ehlo()
if server.has_extn('STARTTLS'):
server.starttls()
server.ehlo()
server.login(ldap, password)
print "%s#abc.com, %s#abc.com, %s "%(email_address,email_address,message.as_string())
server.sendmail('%s#abc.com'%email_address, "%s#abc.com"%email_address, message.as_string())
finally:
server.quit()

Dont put a bunch of code (doing different things) into one try/except block, but you can easily add an if/else condition in your finally block:
def send_email(ldap, email_address, password, msg):
server = None #make sure server variable is always defined.
try:
...
server = smtplib.SMTP(...)
...
finally:
if server and isinstance(x, smtplib.SMTP):
server.quit()

Since your finally block is only used to ensure the server connection is properly closed whatever, the obvious answer is to only wrap the relevant part in the try block:
def send_email(ldap, email_address, password, msg):
message = MIMEMultipart('alternative')
message['To'] = email.utils.formataddr(('Recipient', '%s#abc.com'%email_address))
message['From'] = email.utils.formataddr(('Author', '%s#abc.com'%email_address))
message['Subject'] = 'Sample subject'
text = "%s"%msg
html = MIMEText('<html><head></head><h2>data</h2><body><p>%s</p></body></html>'%msg,'html')
message.attach(html)
server = smtplib.SMTP(host="ip",port=0)
# now you can start the try block:
try:
server.set_debuglevel(True)
# identify ourselves, prompting server for supported features
server.ehlo()
if server.has_extn('STARTTLS'):
server.starttls()
server.ehlo()
server.login(ldap, password)
print "%s#abc.com, %s#abc.com, %s "%(email_address,email_address,message.as_string())
server.sendmail('%s#abc.com'%email_address, "%s#abc.com"%email_address, message.as_string())
finally:
server.quit()
A still better solution would be to split this code in distinct functions each with a single well-defined responsability - preparing the message, getting a connection to the server etc, ie:
def prepare_message(sender, recipient, subject, msg):
message = MIMEMultipart('alternative')
message['To'] = email.utils.formataddr(('Recipient', recipient))
message['From'] = email.utils.formataddr(('Author', sender))
message['Subject'] = subject
#text = "%s" % msg # this one is useless
html = MIMEText("""
<html>
<head></head>
<body>
<h2>data</h2>
<p>%s</p>
</body>
</html>""" % msg,
'html'
)
message.attach(html)
return message
def connect(ldap, password):
server = smtplib.SMTP(host="ip",port=0)
server.set_debuglevel(True)
# identify ourselves, prompting server for supported features
server.ehlo()
if server.has_extn('STARTTLS'):
server.starttls()
server.ehlo()
server.login(ldap, password)
return server
def send_email(ldap, email_address, password, msg):
sender = recipient = "%s#abc.com" % email_address
message = prepare_message(sender, recipient, 'Sample subject', msg)
server = connect(ldap, password)
try:
server.sendmail(sender, recipient, message.as_string())
finally:
server.quit()

Related

sending email with smtp (help needed)

async def test(ctx, arg1, arg2):
_smpt = smtplib.SMTP('mail.cock.li', 587)
_smpt.starttls()
username = ('my email#cock.li')
password = ('my pass')
try:
_smpt.login(username, password)
except:
await ctx.send(f"incorrect password or email")
reciever = (f'{arg1}')
message = (f'{arg2}')
_smpt.sendmail(username, reciever, message)
does anyone know why this is gving me a error im using https://cock.li/server and discord.py bot command
the error is SMTPResponseException: (454, b'4.7.0 TLS not available due to local problem')
Note: change the security settings of your sender mail id such that it allows access to low security apps(can be done manually in mail settings)
Use the following code
import smtplib
s = smtplib.SMTP('smtp.gmail.com', 587)
s.starttls()
sender_email_id=input("sender mail")
sender_email_id_password=input("sender mail password")
s.login(sender_email_id, sender_email_id_password)
message = "Message_you_need_to_send"
receiver_email_id=input("receiver mail")
s.sendmail(sender_email_id, receiver_email_id, message)
s.quit()

Using smtplib to send an email to mailtrap only works when code is not within function or class

this question is somehow similar to python: sending a mail, fails when inside a "with" block .
I'm using Python (3.6) to send emails to mailtrap smtp. Mailtrap actually provides you with the integration code for smtplib which is the one below:
import smtplib
sender = "Private Person <from#smtp.mailtrap.io>"
receiver = "A Test User <to#smtp.mailtrap.io>"
message = f"""\
Subject: Hi Mailtrap
To: {receiver}
From: {sender}
This is a test e-mail message."""
with smtplib.SMTP("smtp.mailtrap.io", 2525) as server:
server.login("<MYUSER>", "<MYPASSWORD>")
server.sendmail(sender, receiver, message)
The code above works just fine if I place it in a module and run it.I go to mailtrap inbox and verify that the email is there. However I want to encapsulate this in a function like this:
import smtplib
from socket import gaierror
def test():
sender = "Test Dev <from#smtp.mailtrap.io>"
receiver = "Test User <to#smtp.mailtrap.io>"
message = f"""\
Subject: Hi there
To: {receiver}
From: {sender}
TESTING"""
try:
with smtplib.SMTP("smtp.mailtrap.io", 2525) as server:
server.login("<MYUSER>", "<MYPASSWORD")
print("Sending email")
server.sendmail(sender, receiver, message)
print('Sent')
except (gaierror, ConnectionRefusedError):
print('Failed to connect to the server. Bad connection settings?')
except smtplib.SMTPServerDisconnected:
print('Failed to connect to the server. Wrong user/password?')
except smtplib.SMTPException as e:
print('SMTP error occurred: ' + str(e))
if __name__ == "__main__":
test()
This doesn't work. WHY? Here is the output:
output image
There's no connection error or any other exception. However I go to mailtrap and don't find the email there.
Is this a mailtrap issue or is it related to smtplib ? I'm cracking my head around this one
I was having this same issue and couldn't wrap my head around it. I did notice that when I made my message an empty string, it worked.
After an embarrassingly long time of searching; I found this post which pointed me to the solution.
You must set the MIME type of the email message. So rather than just passing a string you pass a message object:
message = MIMEText("TEST!")
message["Subject"] = "Alert!"
message["From"] = sender
message["To"] = receiver
... then eventually
server.sendmail(sender, receiver, message.as_string())
my full send email function looks like this:
def send_mail(self):
message = MIMEText("TEST!")
message["Subject"] = "Alert!"
message["From"] = sender
message["To"] = receiver
try:
context = ssl.create_default_context()
with smtplib.SMTP(smtp_server, port) as server:
server.set_debuglevel(1)
server.ehlo() # Can be omitted
server.starttls(context=context)
server.ehlo() # Can be omitted
server.login(login, password)
server.sendmail(sender, receiver, message.as_string())
print('Sent')
except (gaierror, ConnectionRefusedError):
print('Failed to connect to the server. Bad connection settings?')
except smtplib.SMTPServerDisconnected:
print('Failed to connect to the server. Wrong user/password?')
except smtplib.SMTPException as e:
print('SMTP error occurred: ' + str(e))
except Exception as e:
print('everything else')
It's unfortunate that you must specify the sender and receiver in both the message object and sendemail fuction.

Python: How to pass email text body to Office365 Email

Trying to make the script below work for office365. Sends out an email but I cannot get the script to recognize the actual email text body (only the Subject line being sent). Below script worked for gmail. Any ideas where I need to modify?
Thanks!
import smtplib, ssl
port = 587
smtp_server = "smtp.office365.com"
sender_email = "me#email.com"
receiver_email = {'User1': 'user1#email.com'}
password = "password"
subject = input('Enter the subject line: ')
message = input('Enter the message: ')
email = """\
Subject: %s
%s
""" % (subject, message)
for key, value in receiver_email.items():
context = ssl.create_default_context()
with smtplib.SMTP(smtp_server, port) as server:
server.ehlo() # Can be omitted
server.starttls(context=context)
server.ehlo() # Can be omitted
server.login(sender_email, password)
server.sendmail(sender_email, value, email)
server.quit()
was missing a "\n" in the email object. It now works.
email = """\
Subject: %s\n
%s
""" % (subject, message)

should return outside finally and is the exception handled perfectly?

Should I not put the return from this method below in finally ? Pylint gives error for this saying:
3: return statement in finally block may swallow exception (lost-exception)
def sendMessage(self, subject, msgContent, files, mailto):
""" Send the email message
Args:
subject(string): subject for the email
msgContent(string): email message Content
files(List): list of files to be attached
mailto(string): email address to be sent to
"""
msg = self.prepareMail(subject, msgContent, files, mailto)
# connect to server and send email
server=smtplib.SMTP(self.smtpserver, port=self.EMAIL_PORT)
server.ehlo()
# use encrypted SSL mode
server.starttls()
# to make starttls work
server.ehlo()
server.login(self.usrname, self.password)
server.set_debuglevel(self.debug)
try:
failed = server.sendmail(self.mailFrom, mailto, msg.as_string())
except Exception as er:
print er
finally:
server.quit()
if failed:
return False
return True
alright, I fixed the problem, #Nabla pointed the right!!
def sendMessage(self, subject, msgContent, files, mailto):
""" Send the email message
Args:
subject(string): subject for the email
msgContent(string): email message Content
files(List): list of files to be attached
mailto(string): email address to be sent to
"""
msg = self.prepareMail(subject, msgContent, files, mailto)
# connect to server and send email
server = smtplib.SMTP(self.smtpserver, port=self.EMAIL_PORT)
server.ehlo()
# use encrypted SSL mode
server.starttls()
# to make starttls work
server.ehlo()
server.login(self.usrname, self.password)
server.set_debuglevel(self.debug)
try:
server.sendmail(self.mailFrom, mailto, msg.as_string())
except Exception as er:
print er
return False
finally:
server.quit()
return True
This is not a direct answer to your question, but if I may suggest a slightly-different implementation.
Put the connect-to-server and disconnect-from-server in two different methods:
class MyClass():
serverDict = {
"gmail" :"smtp.gmail.com",
"hotmail":"smtp.live.com",
"yahoo" :"smtp.mail.yahoo.com"
}
def __init__(self,username,password):
self.username = username
self.password = password
self.serverName = MyClass.serverDict[username[username.index("#")+1:username.index(".")]]
def sendMessage(self,subject,msgContent,files,mailto):
server = Connect()
if not server:
return False
failed = True
try:
server.login(self.username,self.password)
if not server.sendmail(self.mailFrom,mailto,msg.as_string()):
failed = False
except Exception,error:
print error
Disconnect(server)
return failed
def Connect():
try:
server = smtplib.SMTP(self.serverName)
except smtplib.SMTPException,error:
print error
return None
try:
server.ehlo()
if server.has_extn("starttls"):
server.starttls()
server.ehlo()
except (smtplib.SMTPException,ssl.SSLError),error:
print error
Disconnect(server)
return None
return server
def Disconnect(server):
try:
server.quit()
except smtplib.SMTPException,error:
print error

sending mail from gmail account - Python

could someone kindly tell me, what's wrong with the code below? TIA :)))
import smtplib
if raw_input("if you want to send a message from a gmail account, type yes: ") == 'yes':
try:
sender = raw_input("from:\n")
senders_pwd = raw_input("password:\n")
recipient = raw_input("to:\n")
print 'ok, now compile your message:'
subject = raw_input("subject:\n")
body = raw_input("your message:\n")
message = "subject: %s\n%s" %(subject,body)
server = smtplib.SMTP("smtp.gmail.com",587)
server.ehlo()
server.starttls()
server.ehlo()
print "ok, I've sent your email"
except:
print 'failed to send'
You need to call the sendmail() function. Add something like these three lines after the last server.ehlo():
server.login(sender, senders_pwd)
server.sendmail(sender, recipient, message)
server.close()

Categories

Resources