exchangelib - How to send attachment with email reply - python

I am using exchangelib to connect to exchange and reply to emails. But while sending reply it doesn't support attachments.
As per this answer I have to " create a normal Message item that has a 'Re: some subject' title, contains the attachment, and quotes the original message, if that's needed."
but i am not sure how to "quote" the original message
I am using following code to reply:
from pathlib import Path
from exchangelib import Message, Account, FileAttachment
account = Account(...)
item = ...
file_to_attach = Path('/file/to/attach.txt')
message = Message(
account=account,
subject="Re: " + item.subject,
body="This is reply by code",
cc_recipients=item.cc_recipients,
to_recipients=[item.sender],
in_reply_to=item.id,
conversation_id=item.conversation_id,
)
with file_to_attach.open('rb') as f:
content = f.read()
message.attach(FileAttachment(name=file_to_attach.name, content=content))
message.send_and_save()
It sends the email with attachment but it doesn't maintain text from original mail in reply and appears to be a new mail instead of a reply. also doesn't appear as conversation in gmail
I may be missing something small here. please suggest how to fix this

After spending some more time looking for solution I found this answer in C# using which I was able to achieve the following solution:
attachment = FileAttachment(name=file_name, content=f.read())
reply = item.create_reply("Re: " + item.subject, "THIS IS REPLY FROM CODE" )
msg = reply.save(account.drafts)
msg.attach(attachment)
msg.send()
Hope this helps someone else looking for a solution to similar problem.

Related

Parse email message as HTML while sending email smtplib

I am sending bulk emails with the help of pandas library, There is a problem which I am facing, I want to parse the body text as HTML as there are some HTML tags which I want to use. Following is the code for the same.
message = """\
Dear Student,
Following are your login details,
Email {0}
Password {1}
You may log in via URL mail.sample.com
Do not copy/paste the password.
Regards,
Admin
""".format(student_email,student_password)
full_email = ("From: {0} <{1}>\n"
"To: {2}\n"
"Subject: {3}\n\n"
"{4}"
.format(self_name, self_email, email, subject, message))
I couldn't find any other code with having the same library which I am using currently and if possible I would like to use only these libraries i.e. pandas and smtplib.
Apologies if the redundant question
TL;DR I want to parse text to HTML while sending the email
The problem is if I append tags in message variable it will literally show tags instead of parsing. For ex:
<b>Email : </b>sample#sample.com
You probably want to use the built-in email package, rather than constructing the email by hand. That will let you set the content-type to text/html:
from email.message import EmailMessage
msg = EmailMessage()
msg.set_content(html_message, subtype="html")
msg['Subject'] = subject
msg['From'] = '{0} <{1}>'.format(self_name, self.email)
msg['To'] = email
So after a couple of days of brainstorming, I hacked a way to do this, I had to use a couple of more libs. but that did that the job. Initially, I was not flexible to do so but had to.
Along with pandas and smtplib below are the libraries I have used.
from email.mime.text import MIMEText
from jinja2 import Environment
Here a tradeoff was done, I completely removed the full_email variable, instead of it, the following was done.
message = """\
<p>Dear Student,<p>
<span>Following are your login details,</span><br/><br/>
<b>Email</b> {0} <br/>
<b>Password</b> {1} </br><br/>
You may login via URL sample.mail.com<br/>
Do not copy/paste the password.<br/>
<br/><br/>
Regards,<br/>
""".format(student_email,student_password)
msg = MIMEText(
Environment().from_string(message).render(
title='Hello World!'
), "html"
)
msg['Subject'] = subject
msg['From'] = from
msg['To'] = email
and in order to send it.
server.sendmail(email,[email],msg.as_string())
Thanks to this answer, I was able to achieve it.

Mass Email Via Python, Custom Body

New to Python, I'm trying to write a mass-email script (it will be sent via gmail).
Basically I have got it working, however I need to edit each message body separately with a greeting to name of the e-mail recipient. Currently the body is read off a body.txt file and I am not sure how to edit it. Example:
body.txt
Hi <recipient>,
Here is your voucher code.
And this is my script, send_email.py:
import smtplib
from email.mime.text import MIMEText
from_address = "xyz#gmail.com"
file = open("body.txt","rb")
message = MIMEText(file.read())
file.close()
server = smtplib.SMTP('smtp.gmail.com', 587)
server.starttls()
server.login(from_address, "XXXXX")
server.set_debuglevel(1)
sender = from_address
recipients = ['abc#gmail.com', 'def#gmail.com']
message['Subject'] = "Voucher Code"
message['From'] = sender
message['To'] = ", ".join(recipients)
server.sendmail(sender, recipients, message.as_string())
I think most probably I will have to create another list with the names of recipients and match them to the email addresses to be sent to, but I'm not sure how to go from there. In fact, I'm not even sure this is the best way- it works though, so I'm pretty happy so far, apart from not being able to edit the body. How do I go from here?
I've seen what you did and I think it's a great start. To edit in the recipients name to the message is really quite simple. You need to format the string. Here's an example:
emailBody = "Hello {}, this is my email body. As you can see this program inserts every recipient separately. Hopefully it is helpful. \n"
recipients = ["Ann", "Josh", "Bob", "Marie"]
for recipient in recipients:
print(emailBody.format(recipient))
The main thing is that your emailBody must include symbols {} and then you can use
emailBody.format(content)
to put something into those brackets.

Sending gmail emails through python + smtplib. Can't separate body from subject

I want to send emails from my gmail acocunt through a python script.
And my code works.
The only thing is I want the emails to have a subject and a body.
But my script is putting everything in the subject.
Here's my code:
import smtplib
with smtplib.SMTP("smtp.gmail.com", 587) as smtp:
smtp.ehlo()
smtp.starttls()
smtp.ehlo()
smtp.login("MY EMAIL", "MY PASSWORD")
subject = "Contract Details"
body = "Grettings. Here are the contract details. Thank you."
msg = f"""Subject: {subject}\n\n{body}"""
email = "MY EMAIL"
def encode(x):
""" The replaces in this function fix some problems in the encoding.
For now, they are not that relevant. They work. """
return str(x.encode("ascii", errors="ignore")).replace("b'", "").replace("'", "")
# I'm sending it to myself, so the first two arguments are the same:
smtp.sendmail(encode(email), encode(email), encode(msg))
I've tried to figure out the solution online, and a lot of videos and articles say that you should use two newlines to separate the subject from the body.
That's why I'm using msg = f"""Subject: {subject}\n\n{body}"""
However, I get this:
As you can see both my subject and body are in the subject (red), and the body is blank.
I've also tried no breaklines, one breakline, three breaklines.
I even tried to write msg = f"""Subject: {subject}\n\nBody: {body}"""
But nothing works...
How do I separate the body from the subject?
Ok, so I changed:
smtp.sendmail(encode(email), encode(email), encode(msg))
To:
smtp.sendmail(encode(email), encode(email), msg)
And now it works.

Python Smptlib Email (Wrong subject & message field)

Everytime I send an email with this function, it doesn't add the subject and the message to the right fields, but instead of that, it adds it to the 'from:' or something.
Here's the image of it.
Any idea how this can be fixed? Thanks for answer
import smtplib
## NON-ANONYMOUS EMAIL
def email():
# Parts of an email
SERVER = 'smtp.gmail.com'
PORT = 587
USER = 'something#gmail.com'
PASS = 'something'
FROM = USER
TO = ['something#riseup.net']
#SUBJECT = 'Test'
MESSAGE = 'Test message.'
# Connects all parts of email together
message = "From: %s\r\n To: %s\r\n %s" % (FROM, ", ".join(TO), MESSAGE)
# Sends an email
email = smtplib.SMTP()
email.connect(SERVER,PORT)
email.starttls()
email.login(USER,PASS)
email.sendmail(FROM, TO, message)
email.quit()
email()
You cannot have a space after the \r\n. An email header line is continued by indenting it, so your code is creating a really long From: header with all the data you are trying to put in different fields.
Anyway, manually gluing together snippets of plain text is a really crude and error-prone way to construct an email message. You will soon find that you need the various features of the Python email module anyway (legacy email is 7-bit single part ASCII only; you'll probably want one or more of attachments, content encoding, character set support, multipart messages, or one of the many other MIME features). This also coincidentally offers much better documentation for how to correcty create a trivial email message.
Following on from #tripleee suggestion to use the email module, here's a basic example using your current code:
import smtplib
from email.mime.text import MIMEText
## NON-ANONYMOUS EMAIL
def email():
# Parts of an email
SERVER = 'smtp.gmail.com'
PORT = 587
USER = 'something#gmail.com'
PASS = 'something'
FROM = USER
TO = ['something#riseup.net']
SUBJECT = 'Test'
# Create the email
message = MIMEText('Test message.')
message['From'] = FROM
message['To'] = ",".join(TO)
message['Subject'] = SUBJECT
# Sends an email
email = smtplib.SMTP()
email.connect(SERVER,PORT)
email.starttls()
email.login(USER,PASS)
email.sendmail(FROM, TO, message.as_string())
email.quit()
Notice how much easier it is to define the parts of the email using keys like message['Subject'] instead of attempting to build a string or 'gluing parts together' as tripleee put it.
The different fields (From, To, Subject, et cetera) you can access are defined in RFC 2822 - Internet Message Format.
These documents are not easy to read, so here's a list of some of the fields' keys you can use: To, From, Cc, Bcc, Reply-To, Sender, Subject.
You cannot have a space after the \r\n. An email header line is continued by indenting it, so your code is creating a really long From: header with all the data you are trying to put in different fields.
As triplee and the RFC-2822 document says, if you are wanting to build the email string manually look at the field definitions in that document which look similar to this example:
from = "From:" mailbox-list CRLF
You can translate this into Python code when building an email string like so:
"From: something#riseup.net \r\n"
I was able to get mine to work using:
("From: %s\r\nTo: %s\r\nSubject: %s\r\n\r\n%s"
% (gmail_user, recipient, subject, body))

How to send a properly formatted email using Python and SMTP?

I am trying to send an email using Python script but somehow in the format I am expecting the email to come in my mailbox, it is not coming in that format. Below is my method which is sending an email -
def send_mail(data):
sender = 'fromuser#host.com'
receivers = ['touser#host.com']
message = """From: fromuser#host.com
To: touser#host.com
Subject: Send mail from python!!
"""
body = 'Some Text\n'
for item in data:
body = body + '{name} - {res}\n'.format(name=item['name'], res=item['res'])
message = message + body
try:
smtpObj = smtplib.SMTP('corp.host.com' )
smtpObj.sendmail(sender, receivers, message)
print "Mail sent"
except smtplib.SMTPException:
print "You can't spam. Mail sending failed!"
Here data just have key - value pair.
And I am getting an email like this in my Outlook mailbox -
In the From: section in my outlook, below string is coming as it is which is wrong -
fromuser#host.com To: touser#host.com Subject: Send mail from python!!
And To: , Subject: section is coming as Empty which is also wrong.
And in the body I am seeing everything coming in a single line but I want the result to be shown as -
Some Text
machinA - 0
machineB - 0
machineC - 0
How can I represent my data to be shown like this in my Outlook mailbox?
Since triple quoting preserves all spaces, you were accidentally sending:
From: fromuser#host.com
To: touser#host.com
Subject: Send mail from python!!
This invokes header unfolding: indented lines mean that the header is continued. So this really is a badly formatted From header. You need to make sure there are no extraneous spaces. This fixes up your current example:
def send_mail(data):
sender = 'fromuser#host.com'
receivers = ['touser#host.com']
message = """\
From: fromuser#host.com
To: touser#host.com
Subject: Send mail from python!!
"""
body = '\n\nSome Text\n'
for item in data:
body = body + '{name} - {res}\n'.format(name=item['name'], res=item['res'])
message = message + body
try:
smtpObj = smtplib.SMTP('corp.host.com' )
smtpObj.sendmail(sender, receivers, message)
print "Mail sent"
except smtplib.SMTPException:
print "You can't spam. Mail sending failed!"
However, you shouldn't be manually constructing messages at all. Python includes an assortment of lovely classes in email.message for constructing a message.
import email.message
m = email.message.Message()
m['From'] = "fromuser#host.com"
m['To'] = "touser#host.com"
m['Subject'] = "Send mail from python!!"
m.set_payload("Your text only body");
Now, you can turn your message into a string:
>>> m.as_string()
'To: touser#host.com\nFrom: fromuser#host.com\nSubject: Send mail from python!!\n\nyour text-only body'
I will warn you, properly dealing with email is a very large and complex topic, and if you want to use non-ascii, attachments, etc, there's a bit of a learning curve, and you will need to use all the faculties of the email.message library, which has a lot of documentation you should read and understand.

Categories

Resources