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

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.

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.

exchangelib - How to send attachment with email reply

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.

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))

Beginner - subject line in emails

I've written a very basic script in Python that allows me to send emails more quickly/easily. I don't really intend to use it day to day, it's more a proof of concept for myself.
I can't get the subject line to appear though. I can send emails but when I try to include the subject line with the method I describe at the bottom of this question it just doesn't send the email (I'm aware the subject is currently commented out!). Here is my code currently:
import smtplib
candidate_name = raw_input("Candidate Name: ")
candidate_email = raw_input("Candidate Email: ")
# Specifying the from and to addresses
fromaddr = 'XXXX'
toaddrs = '%s' % candidate_email
#subject = 'Phone call'
# Writing the message (this message will appear in the email)
msg = '''
Hi %s
Thanks for taking my call just now. As discussed if you could send me a copy of your CV that would be great and I'll be back in touch shortly.
Cheers
XXXX''' %candidate_name
username = 'XXXX'
password = 'XXXX'
# Sending the mail
server = smtplib.SMTP('XXXX')
server.starttls()
server.login(username,password)
server.sendmail(fromaddr, toaddrs, msg)
print "Email sent to %s at %s" % (candidate_name, candidate_email)
server.quit()
I tried adding subject to the send mail line like this:
server.sendmail(fromaddr, toaddrs, subject, msg)
But it didn't do anything.
I hope this isn't a really stupid question. I'm only starting out teaching myself Python.
Declaration of SMTP.sendmail:
SMTP.sendmail(from_addr, to_addrs, msg[, mail_options, rcpt_options])
It expects the subject as part of the message, and the message to be the third argument passed. You're moving the message to the fourth argument and sending it and the subject separately.
You can a attach it as a header:
msg = 'Subject: %s\n%s' % (subject_text, message_text)
server = smtplib.SMTP(SERVER)
server.sendmail(fromaddress, toaddress, msg)
server.quit()
You should consider using standard Python module email - it will help you a lot while composing emails.
See specify-a-sender-when-sending-mail..., the subject is a mime header.
You can utilize the email.message.Message class, and use it to generate mime headers, including from:, to: and subject.
Send the as_string() result using smtplib (see other answers).
>>> from email import message
>>> m1=message.Message()
>>> m1.add_header('from','me#no.where')
>>> m1.add_header('to','myself#some.where')
>>> m1.add_header('subject','test')
>>> m1.set_payload('test\n')
>>> m1.as_string()
'from: me#no.where\nto: myself#some.where\nsubject: test\n\ntest\n'
>>>

Categories

Resources