Parse email message as HTML while sending email smtplib - python

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.

Related

Text not showing when sending html gmail using python

Im trying to send gmail email using python. The email includes plain text and an html image to be shown in the email. However when i try sending the email, the text is not showing (only image is shown).
Below is the code:
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
host='smtp.gmail.com'
port=587
username='sender#gmail.com'
password='mypassword'
from_email=username
to_list=['recipient#gmail.com']
email_conn=smtplib.SMTP(host,port)
email_conn.ehlo()
email_conn.starttls()
email_conn.login(username,password)
msg=MIMEMultipart('Alternative')
temp=MIMEMultipart('Alternative2')
msg['Subject']='Hello'
msg['From']=username
txt='Welcome home'
part1=MIMEText(txt,'plain')
msgText = MIMEText('<img src="cid:image1">', 'html')
temp.attach(msgText)
fp = open('/home/user/Pictures/image.jpg', 'rb')
msgImage = MIMEImage(fp.read())
fp.close()
# Define the image's ID as referenced above
msgImage.add_header('Content-ID', '<image1>')
temp.attach(msgImage)
msg.attach(part1)
msg.attach(temp)
email_conn.sendmail(from_email,to_list,msg.as_string())
email_conn.quit()
The immediate error is that you are creating a invalid MIME part with type multipart/Alternative2. You seem to be confusing the type (which should be one out of a limited set of IANA-approved labels) with a unique identifier.
More fundamentally, you seem to be following some obsolete email guideline. The proper way to create a new message in Python 3.6+ is to use the (no longer very) new EmailMessage API.
Also, you will want to restructure your code so that the message creation is not mixed with the message sending. In the following, I have simply removed all the smtplib code; this also makes it easy for you to troubleshoot locally with print(msg.as_string()) instead of sending the message.
from email.message import EmailMessage
from email.utils import make_msgid
username = 'sender#gmail.com'
to_list = ['recipient#gmail.com']
msg = EmailMessage()
msg['Subject'] = 'Hello'
msg['From'] = username
# Need recipient!
msg['To'] = ', '.join(to_list)
msg.set_content('Welcome home')
image_id = make_msgid()
# Notice closing slash at the end of <img ... />
msg.add_alternative('<img src="%s" />' % image_id.strip('<>'), subtype='html')
with open('/home/user/Pictures/image.jpg', 'rb') as fp:
msg.get_payload()[1].add_related(
fp.read(), 'image', 'jpeg', cid=image_id)
This rather closely follows the "asparagus" example from the email examples in the documentation.
You would then go on to create an SMTP session and smtp.send_message(msg) rather than take the detour to separately and explicitly convert the message to a string you can pass to the legacy sendmail method; this is one of the many improvements in the new API.

Display username in the mail sent from smtplib

I have written a python script to send mail using smtplib.
Everything is working fine except, when the user receives the mail, he isn't able to see my google account name, instead he is getting the mail id. is there a way to make this right?
I guess it's got to do something here but am not sure.
msg = MIMEMultipart()
msg['From'] = from_addr
msg['To'] = ','.join(recipients_addr)
msg['Subject'] = subject
msg.attach(MIMEText(body, 'plain'))
return msg
The first image is the one sent with smtplib. There is no username.
The second one is sent normally from gmail.
You need to provide both the email address and the account name to do this.
The email.utils.formataddr function can be used to format the data:
>>> from email import utils
>>> utils.formataddr(('Jane Smith', 'jsmith#example.com'))
'Jane Smith <jsmith#example.com>'
In the code the question, you would do something like
from_addr = 'praneeth.vasarla#example.com'
from name = 'Praneeth Vasarla'
msg['from'] = formataddr((from_name, from_addr))

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

Categories

Resources