I wrote a script for backing up my Neo4J DB.
At the end of the backup process and email is sent to the DB Administrator
The email received without the message_body.
This is the code:
message = MIMEMultipart('alternative')
message['To'] = "Database Admin <%s>" % _receiver
message['From'] = "Pico.buzz Graph Database <%s>" % _sender
if not log.is_error():
message['Subject'] = "Graph DB Backup Finished Successfully"
message_body = 'Successfully backup email. Please see review log file'
else:
message['Subject'] = "ATTENTION: ERROR! Graph DB Backup Failed"
message_body = 'An error occur during backup. please review log'
instance_name = aws.get_instance_name()
instance_details = "Instance Id: %s\nPrivate IP Address: %s" % (aws.get_instance_id(), aws.get_instance_ip())
if instance_name is not None:
instance_details = """Instance Name: %s\n%s""" % (instance_name, instance_details)
message_body = "%s\n\n%s" % (message_body, instance_details)
content = MIMEText(message_body, 'plain')
message.attach(content)
message.attach(_get_log_file())
smtp = smtplib.SMTP('localhost')
smtp.sendmail(_sender, _receiver, message.as_string())
log.info(__name__, "Successfully sent email to: %s" % _receiver)
Any idea why?
MIMEMultipart takes as a parameter to the constructor a multipart subtype.
You were using the subtype 'alternative'. The alternative subtype allows the email to be sent with HTML and text.
You wanted to submit an email with text and an attachment, so you need to construct MIMEMultipart with the subtype 'mixed'.
For more details about these subtypes, you can look at the MIME Wikipedia entry on Multipart messages.
Related
I have an email object of an unread email. How do I reply to the email using SMTP lib using the specific email object i.e. (if mail comes from flipkart, the particular mail has an object. I want to reply using that mail object)? I tried using msg['Reply_To'] and I got an error saying the email id is not valid. I did check the smtp documentation and couldn't find anything regarding the same. Here when I comment the [send to] and only add [reply to] the error is shown below. But when I uncomment the same the mail is sent but it is not sent as a reply. This shows that the email id is correct.
CODE:
def SendReply(self):
self.msg["from"] = self.From
self.msg["Cc"] = self.cc
self.msg["To"] = self.To
self.msg["Subject"] = self.Subject
self.Body = str(self.Body)
self.msg["Reply_To"] = self.Reply_To
self.msg.set_content(self.Body)
# print("Print this now", self.msg["Reply_To"])
if self.Attachments is not None:
with open(self.Attachments, "rb") as f:
file_data = f.read()
self.msg.add_attachment(
file_data,
maintype="application",
subtype="xlsx",
filename=self.Attachments,
)
with smtplib.SMTP("smtp.gmail.com", 587) as smtp:
smtp.starttls()
smtp.login(self.From, self.EmailPassword)
self.msg["Reply_To"] = self.Reply_To
smtp.send_message(self.msg)
return ("Mail sent Succesfully", True)
ERROR:
smtplib.SMTPRecipientsRefused:
{'None': (553,
b'5.1.3 The recipient address <None> is not a valid RFC-5321 address.
Learn\n5.1.3 more at\n5.1.3 https://support.google.com/mail/answer/6596 ij25-20020a170902ab5900b0016beceac426sm3191763plb.138 - gsmtp')}
Friends
I have posted a Code below I have written the code as I want to send an email when the productqty = 0. Then an email should be sent to the admin. For this condition, I have fetched the value from the request form and stored it in the variable called ProductQty and I have used that variable in the " if " condition according to the when the condition becomes true the def function is called (email_alert) and the email should be sent to the prakprak2002#gmail but the email is not getting. Please if possible any suggestions or solutions to the problem.
thankyou and sorry about my bad English grammar.
#app.route('/editProduct',methods = ['POST'])
def editProduct():
if request.method == 'POST' and 'ProductID' in request.form and 'NEWProductName' in request.form and 'NEWProductDescription' in request.form and 'NEWProductQty':
try:
productID = request.form['ProductID']
productName = request.form['NEWProductName']
productDescription=request.form['NEWProductDescription']
ProductQty=request.form['NEWProductQty']
cursor = mysql.connection.cursor()
cursor.execute("UPDATE Products SET productName = % s,productDescription = % s, QTY = % s WHERE productID = % s",(productName,productDescription,ProductQty,productID) )
msg = "Product Edited "
mysql.connection.commit()
cursor.close()
if ProductQty <= 0:
email_alert('prakprak2002#gmail.com')
except:
#con.rollback()
msg = "error in operation"
finally:
return redirect(url_for('product', msg = msg))#+"?msg="+msg)
#con.close()
The above code is the route.
The below code is the email_alert function.
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
mail_content = ''' Hello,
This is a simple mail. There is only text, no attachments are there. The mail is sent.
Thankyou '''
#The mail addresses and password
def email_alert(receiver_address):
sender_address = 'email'#intentionally wrote
sender_pass = 'password'#intentionally wrote
receiver_address = receiver_address
#Setup the MIME
message = MIMEMultipart()
message['From'] = sender_address
message['to'] = receiver_address
message['Subject'] = 'A test mail sent by Python. It has an attachment.'
#The body and the attachments for the mail
message.attach(MIMEText(mail_content, 'plain'))
#Create SMTP session for sending the mail
session = smtplib.SMTP('smtp.gmail.com', 587) #use gmail with port
session.starttls() #enable security
session.login(sender_address, sender_pass) #login with mail_id and password
text = message.as_string()
session.sendmail(sender_address, receiver_address, text)
session.quit()
print('Mail Sent')
Have you considered using flask_mail extension for flask. You could send an E-Mail as easy as that:
from flask_mail import Message
from app import mail
def send_email(subject, sender, recipients, html_body):
msg = Message(subject, sender=sender, recipients=recipients)
msg.html = html_body
mail.send(msg)
You should also consider sending it as an Asynchronous call, since it can take a while. You can find detailled information on how it can be implemented under the following link:
https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-xi-email-support
And please consider using SQL expression language, instead of raw SQL to prevent SQL Injection.
You have not revealed how this is failing; I would assume that the problem is that Gmail rejects the connection because you failed to do the ehlo() again after startls(). (Yes, it's a bit crazy that they require this; but they do.)
Tangentially, you should probably update your email code to use the Python 3.6+ EmailMessage module.
import smtplib
from email.message import EmailMessage
# Don't put a space before the text. Fix typos.
mail_content = '''Hello,
This is a Simple mail. There is only text, no attachments are there. The mail is sent.
Thank you.'''
#The mail addresses and password
def email_alert(receiver_address):
sender_address = 'email'
sender_pass = 'password'
# Comment out, utterly pointless
# receiver_address = receiver_address
message = EmailMessage()
message['From'] = sender_address
message['to'] = receiver_address
# Don't lie i the subject
message['Subject'] = 'A test mail sent by Python. It has no attachment.'
message.set_content(mail_content)
# Use a context manager
with smtplib.SMTP('smtp.gmail.com', 587) as session:
# EHLO is required ... twice
session.ehlo()
session.starttls()
session.ehlo()
session.login(sender_address, sender_pass)
# Prefer send_message
session.send_message(message)
# Probably don't print anything
print('Mail Sent')
I'm trying to read an email, get the headers (from, to, cc, subject) and body of an email and forward the email (forwarding email will vary based on the from).
I've referenced the post to write my code. I was able to forward few emails, but few fail.
import smtplib, imaplib, email
imap_host = "imap-mail.outlook.com"
smtp_host = "smtp-mail.outlook.com"
imap_port = 993
smtp_port = 587
user = "aaa#bbb.com"
passwd = "****"
### Testing random emails using msgid
msgid = 5000
from_addr = "aaa#bbb.com"
to_addr = "ccc#ddd.com"
client = imaplib.IMAP4_SSL(imap_host, imap_port)
client.login(user, passwd)
client.select('INBOX')
status, data = client.fetch(str(msgid), "(RFC822)") #(RFC822) or (UID BODY[TEXT])
email_data = data[0][1]
client.close()
client.logout()
message = email.message_from_bytes(email_data)
message.add_header('From', from_addr) #also tried replace_header
message.replace_header('To', to_addr)
smtp = smtplib.SMTP(smtp_host, smtp_port)
smtp.starttls()
smtp.login(user, passwd)
smtp.sendmail(from_addr, to_addr, message.as_string())
# smtp.send_message(message, from_addr, to_addr)
smtp.quit()
Here is the error, I receive:
554, b'5.2.0 STOREDRV.Submission.Exception:StoragePermanentException.MapiExceptionDuplicateDelivery; Failed to process message due to a permanent exception with message Cannot get ID from name.
Also, any suggestions on how to make the email look like a forward i.e., include the headers of the original email in the body of the forward (as if forwarded from web outlook or the outlook app). Thanks
I am trying to create and save message to Drafts in gmail, but nothing happen.
import time
import random
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import imaplib
def save_draft(email_to, body, login, password, image):
msg = MIMEMultipart("alternative")
msg.set_charset("utf-8")
msg.attach(MIMEText(body, "plain", "utf-8"))
msg['Subject'] = SUBJECT
msg['From'] = login
msg['To'] = email_to
with open(image, 'rb') as f:
part = MIMEApplication(
f.read(),
Name=image
)
part['Content-Disposition'] = 'attachment; filename={}'.format(IMAGE)
msg.attach(part)
imap = imaplib.IMAP4_SSL("imap.gmail.com", 993)
imap.login(login, password)
imap.select('[Gmail]/Drafts')
now = imaplib.Time2Internaldate(time.time())
imap.append('[Gmail]/Drafts',
'',
now,
msg.as_bytes())
imap.logout()
When I am changing msg.as_bytes() to msg.as_string(), I got the error below:
TypeError: cannot use a bytes pattern on a string-like object
If you are using Python library here is the code snippet:
def create_message(sender, to, subject, message_text):
"""Create a message for an email.
Args:
sender: Email address of the sender.
to: Email address of the receiver.
subject: The subject of the email message.
message_text: The text of the email message.
Returns:
An object containing a base64url encoded email object.
"""
message = MIMEText(message_text)
message['to'] = to
message['from'] = sender
message['subject'] = subject
return {'raw': base64.urlsafe_b64encode(message.as_string())}
Once you have created a Message object, you can pass it to the drafts.create method to create a Draft object.
def create_draft(service, user_id, message_body):
"""Create and insert a draft email. Print the returned draft's message and id.
Args:
service: Authorized Gmail API service instance.
user_id: User's email address. The special value "me"
can be used to indicate the authenticated user.
message_body: The body of the email message, including headers.
Returns:
Draft object, including draft id and message meta data.
"""
try:
message = {'message': message_body}
draft = service.users().drafts().create(userId=user_id, body=message).execute()
print 'Draft id: %s\nDraft message: %s' % (draft['id'], draft['message'])
return draft
except errors.HttpError, error:
print 'An error occurred: %s' % error
return None
Also, here is a related SO post that stated: you have decode the bytes object to produce a string.
Hope this helps.
I'm trying to catch all emails that bounced when sending them via smtplib in Python. I looked at this similar post which suggested adding an exception catcher, but I noticed that my sendmail function doesn't throw any exceptions even for fake email addresses.
Here is my send_email function which uses smtplib.
def send_email(body, subject, recipients, sent_from="myEmail#server.com"):
msg = MIMEText(body)
msg['Subject'] = subject
msg['From'] = sent_from
msg['To'] = ", ".join(recipients)
s = smtplib.SMTP('mySmtpServer:Port')
try:
s.sendmail(msg['From'], recipients, msg.as_string())
except SMTPResponseException as e:
error_code = e.smtp_code
error_message = e.smtp_error
print("error_code: {}, error_message: {}".format(error_code, error_message))
s.quit()
Sample call:
send_email("Body-Test", "Subject-Test", ["fakejfdklsa#jfdlsaf.com"], "myemail#server.com")
Since I set the sender as myself, I am able to receive the email bounce report in my sender's inbox:
<fakejfdklsa#jfdlsaf.com>: Host or domain name not found. Name service error
for name=jfdlsaf.com type=A: Host not found
Final-Recipient: rfc822; fakejfdklsa#jfdlsaf.com
Original-Recipient: rfc822;fakejfdklsa#jfdlsaf.com
Action: failed
Status: 5.4.4
Diagnostic-Code: X-Postfix; Host or domain name not found. Name service error
for name=jfdlsaf.com type=A: Host not found
Is there a way to get the bounce message through Python?
import poplib
from email import parser
#breaks with if this is left out for some reason (MAXLINE is set too low by default.)
poplib._MAXLINE=20480
pop_conn = poplib.POP3_SSL('your pop server',port)
pop_conn.user(username)
pop_conn.pass_(password)
#Get messages from server:
messages = [pop_conn.retr(i) for i in range(1, len(pop_conn.list()[1]) + 1)]
# Concat message pieces:
messages = ["\n".join(mssg[1]) for mssg in messages]
#Parse message intom an email object:
messages = [parser.Parser().parsestr(mssg) for mssg in messages]
for message in messages:
if "Undeliverable" in message['subject']:
print message['subject']
for part in message.walk():
if part.get_content_type():
body = str(part.get_payload(decode=True))
bounced = re.findall('[a-z0-9-_\.]+#[a-z0-9-\.]+\.[a-z\.]{2,5}',body)
if bounced:
bounced = str(bounced[0].replace(username,''))
if bounced == '':
break
print bounced
Hope this helps. This will check the contents of the mailbox for any undeliverable reports and read the message to find the email address that bounced.It then prints the result
You can use this function for gmail, basically checking the inbox that whether there is any email from Mail Delivery Subsystem with particular Text in body
def is_email_bounced(email, app_password, email_in_question):
obj = imaplib.IMAP4_SSL('imap.gmail.com',993)
obj.login(email, app_password)
obj.select() # Default Inbox
typ, data = obj.search(None, f'(TEXT "{email_in_question}") (Subject "Delivery Status Notification (Failure)")')
try: data.remove(b'')
except: pass
if len(data) >= 1: return True
else: return False
run this function after sending the email, and check whether email got bounced or not
e.g.
send_email("Body-Test", "Subject-Test", ["fakejfdklsa#jfdlsaf.com"], "myemail#server.com")
if is_email_bounced("youremail#gmail.com", "app_password", "email_in_ques_404#gmail.com"):
print("Email Bounced")
Change email Subject "Delivery Status Notification (Failure)" as per your email service provider, for this code, I've considered email provider as gmail