I am sending a mail by reading an excel file using pandas as dataframe. Then I am converting that dataframe using df.to_html with CSS style wrapped. Below is my code.
from email.mime.text import MIMEText
import email.message
import numpy as np
import pandas as pd
import email
import smtplib
import xlrd
filename = 'exl_sheet.xls'
df = pd.read_excel(filename)
html_string = '''
<html>
<head><title>HTML Pandas Dataframe with CSS</title></head>
<link rel="stylesheet" type="text/css" href="df_style.css"/>
<body>
{table}
</body>
</html>.
'''
df_html = html_string.format(table=df.to_html(classes='mystyle'))
sender = "sender#gmail.com"
receiver = "receiver#gmail.com"
password = 'xxxxxxxxx'
server = 'smtp.gmail.com:587'
msg = email.message.EmailMessage()
msg['Subject'] = 'Train Data'
msg['From'] = sender
msg['To'] = receiver
msg = MIMEText(df_html, 'html')
print(msg)
server = smtplib.SMTP(server)
server.ehlo()
server.starttls()
server.login(sender, password)
server.sendmail(sender, receiver, msg)
server.quit()
The output of print(msg) is :
enter image description here
However, the message I am receiving is as below :
enter image description here
That is I am not receiving the table with style. Please suggest.
First, I believe that only inline styles are supported on email -- at least that's all you can depend on across all email clients. For example, Gamil strips out all <head> and <body> tags. Try adding style parameters to your HTML tags, for example:
<span style="color: red;">I am red</span>
Even if you could have external style sheets, you specified: href="df_style.css", which is a relative URL. If you sent that email to me, would I have that stylesheet on my PC? You would need to make it an absolute URL, such as href="http://demo.com/df_syle.css". Keep this in mind when you reference other items in your email, such as images.
Related
Here is my code
import sys
import smtplib
import imghdr
from email.message import EmailMessage
from tkfilebrowser import askopenfilename
from email.mime.base import MIMEBase
from email.encoders import encode_base64
from email import encoders
def send():
msg = EmailMessage()
msg['Subject'] = body
msg['From'] = 'sender#gmail.com'
msg['To'] = 'receiver#gmail.com'
it worked well until i added this below to attach an image
with open('DSC_0020.jpg', 'rb') as f:
mime = MIMEBase('image', 'jpg', filename="DSC_0020.jpg")
mime.add_header('Content-Dispotion', 'attachment', filename="DSC_0020.jpg")
mime.add_header('X-Attachment-Id', '0')
mime.add_header('Content-ID', '<0>')
mime.set_payload(f.read())
encoders.encode_base64(mime)
mime.attach(mime)
msg.set_content('This is a plain text email')
msg.add_alternative("""\
<DOCTYPE html>
<html>
<body>
<h1 style="color:gray;"> This is an HTML Email! </h1>
<img src="body">
</body>
</html>
""", subtype='html')
with smtplib.SMTP_SSL('smtp.gmail.com', 465) as smtp:
smtp.login('sender51#gmail.com', 'password')
smtp.send_message(msg)
here is the error i get can someone tell me what im doing wrong
File "C:\Users\my name\AppData\Local\Programs\Python\Python38\lib\email\message.py", line 210, in attach
raise TypeError("Attach is not valid on a message with a"
TypeError: Attach is not valid on a message with a non-multipart payload
The main part of the email message should be of type MIMEMUltipart and then text content should be of type MIMEText as follows:
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
# and, of course, other imports
msg = MIMEMultipart('alternative') # to support alternatives
msg['Subject'] = body
msg['From'] = 'sender#gmail.com'
msg['To'] = 'receiver#gmail.com'
with open('DSC_0020.jpg', 'rb') as f:
mime = MIMEBase('image', 'jpg', filename="DSC_0020.jpg")
mime.add_header('Content-Disposition', 'attachment', filename="DSC_0020.jpg") # corrected header
mime.add_header('X-Attachment-Id', '0')
mime.add_header('Content-ID', '<0>')
mime.set_payload(f.read())
encode_base64(mime) # improved statement (you can now get rid of following import: from email import encoders)
msg.attach(mime) # corrected statement
# Attach the plain text as first alternative
msg.attach(MIMEText('This is a plain text email', 'plain'))
# Attach html text as second alternative
msg.attach(MIMEText("""\
<DOCTYPE html>
<html>
<body>
<h1 style="color:gray;"> This is an HTML Email! </h1>
<img src="body">
</body>
</html>
""", 'html'))
You had some errors in your file processing block, which I tried to correct. There may have been others I did not catch.
I am sending mail with html content using 'smtplib' in python , I want to add dynamic content to that html.
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
message = MIMEMultipart("alternative")
message["Subject"] = "Error Notification"
message["From"] = sender
message["To"] = sender
# Create the plain-text and HTML version of your message
html = """\
<html>
<body>
<p>Hi,<br>
<span>Something went wrong !</span><br>
</p>
</body>
</html>
"""
part1 = MIMEText(html, "html")
# Add HTML/plain-text parts to MIMEMultipart message
message.attach(part1)
try:
smtpObj = smtplib.SMTP('localhost')
smtpObj.sendmail(sender, receivers, message.as_string())
print "Successfully sent email"
except smtplib.SMTPException:
print "Error: unable to send email"
Along with the above html I need to include some of my dynamic contents inside the body tag
Since this is Python you can do really awesome things with strings. Just name certain areas of the html with special names and then use the replace method to replace them with whatever value you want.
html = """\
<html>
<body>
<p>Hi, $(name)<br>
<span> $(error) </span><br>
</p>
</body>
</html>
"""
html = html.replace("$(name)", "John")
html = html.replace("$(error)", "Something went wrong!")
print(html)
To include the dynamic content, just get the data from your data source and concatenate them to the body of the mail as per your need.
i am new to python,and below is the code which is suppose to send mail to multiple receipent but only dipeshyog94#gmail.com is getting a mail. milanthapa898#gmail.com which is second on To and alexlee94#gmail.com which is on cc is no getting the mail
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email import encoders
import smtplib
owner_emp_id_email = "dipeshyogi94#gmail.com,milanthapa989#gmail.com"
mymail='milanthapa898#gmail.com'
msg = MIMEMultipart()
msg['From'] = mymail
msg['To'] = owner_emp_id_email
cc_mail = "alexlee94#gmail.com"
msg['Cc'] = cc_mail
print('####44444444444444########\n')
print(owner_emp_id_email)
msg['Subject'] = 'Automated Test Mail with python'
a = 'Milan Thapa'
#body = 'Dear '+spoc_name+',\n\nYou have created new job with below Details:\n\nProject ID : '+project_ID+'\n\nProject Name : '+ibu_name+'\n\nJob Description : ' +job_description +'\n\nThanks and Regards,\n\nMilan Thapa'
html = """\
<html>
<head></head>
<body>
<p>'Dear <b>{}<b>
</p>
</body>
</html>
""".format(a)
msg.attach(MIMEText(html,'html'))
text = msg.as_string()
try:
server = smtplib.SMTP('smtp.gmail.com:587')
except:
server = smtplib.SMTP('smtp.gmail.com:587')
server.ehlo()
server.starttls()
server.ehlo()
server.login(mymail,'password')
server.sendmail(mymail,owner_emp_id_email,text)
server.quit()
i am stuck in this couldn't send the mail to multiple users.
any help will be greatly appreciated!
thanks in advance
The information in the headers doesn't control where the message actually goes. The second argument to sendmail is the only place where this is controlled. This value should be a list, not a comma-separated string.
owner_emp_id_email = "dipeshyogi94#gmail.com,milanthapa989#gmail.com"
env_rcpts = owner_emp_id_email.split(",")
# ...
cc_mail = "alexlee94#gmail.com"
env_rcpts.append(cc_mail)
# ...
server.sendmail(mymail,env_rcpts,text)
You'll notice that you could also add addresses which are neither in To: or Cc: (or a number of other headers which serve the same purpose) to effectively implement Bcc:
Maybe also look at send_message which saves you from having to separately convert your message to a string you can pass to sendmail.
msg['To'] = owner_emp_id_email
Here owner_emp_id_email is a string.
Make it a list of email ids. Then it would work.
to_ids = owner_emp_id_email.split(',')
msg['To'] = to_ids
>>> help(smtplib)
to_addrs: A list of addresses to send this mail to. A bare string will be treated as a list with 1 address.
You need to convert your CSV string to a list like mentioned in the the other answer. With this answer I just wanted to demonstrate how can we use the python's amazing help function when stuck.
I am newbie to Python. I wanted to send html based email with company logo embedded on top left to the email body.
With the following code the email is absolutely working but not attaching the embedded image anymore. Not sure where i did mistake. Can anyone please help me out here.
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.MIMEImage import MIMEImage
msg = MIMEMultipart('alternative')
msg['Subject'] = "My text dated %s" % (today)
msg['From'] = sender
msg['To'] = receiver
html = """\
<html>
<head></head>
<body>
<img src="cid:image1" alt="Logo" style="width:250px;height:50px;"><br>
<p><h4 style="font-size:15px;">Some Text.</h4></p>
</body>
</html>
"""
# The image file is in the same directory as the script
fp = open('logo.png', 'rb')
msgImage = MIMEImage(fp.read())
fp.close()
msgImage.add_header('Content-ID', '<image1>')
msg.attach(msgImage)
part2 = MIMEText(html, 'html')
msg.attach(part2)
mailsrv = smtplib.SMTP('localhost')
mailsrv.sendmail(sender, receiver, msg.as_string())
mailsrv.quit()
I figured out the issue. Here is the updated code for your referance.
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.MIMEImage import MIMEImage
msg = MIMEMultipart('related')
msg['Subject'] = "My text dated %s" % (today)
msg['From'] = sender
msg['To'] = receiver
html = """\
<html>
<head></head>
<body>
<img src="cid:image1" alt="Logo" style="width:250px;height:50px;"><br>
<p><h4 style="font-size:15px;">Some Text.</h4></p>
</body>
</html>
"""
# Record the MIME types of text/html.
part2 = MIMEText(html, 'html')
# Attach parts into message container.
msg.attach(part2)
# This example assumes the image is in the current directory
fp = open('logo.png', 'rb')
msgImage = MIMEImage(fp.read())
fp.close()
# Define the image's ID as referenced above
msgImage.add_header('Content-ID', '<image1>')
msg.attach(msgImage)
# Send the message via local SMTP server.
mailsrv = smtplib.SMTP('localhost')
mailsrv.sendmail(sender, receiver, msg.as_string())
mailsrv.quit()
In case you want something simple:
from redmail import EmailSender
email = EmailSender(host="smtp.myhost.com", port=1)
email.send(
sender="me#example.com",
subject="Example email",
receivers=["you#example.com"],
html="""
<h1>Hi, take a look at this image:</h1>
{{ my_image }}
""",
body_images={"my_image": "path/to/image.png"}
)
The image is embedded to the HTML using Jinja and it creates the img tag automatically. You may also directly pass bytes, matplotlib.Figure or PIL.Image.Image to body_images as well if you prefer those formats.
In case you want more control on the image's properties, like change the width and height:
email.send(
sender="me#example.com",
subject="Example email",
receivers=["you#example.com"],
html="""
<h1>Hi, take a look at this image:</h1>
<img src="{{ my_image.src }}" width=500 height=350>
""",
body_images={"my_image": "path/to/image.png"}
)
Pip install it from PyPI:
pip install redmail
There is a lot the library can do: include attachments from various forms, prettify and embed tables to HTML body, load templates from disk, parametrize etc. It is also well tested (100 % test coverage) and documented. I'm the author of the library and sorry for the self-promotion. I think it's awesome and worth sharing.
Documentation: https://red-mail.readthedocs.io/en/latest/index.html
Source code: https://github.com/Miksus/red-mail
I'm currently using the following code to send an email (which contains a report) to users 3 times per day. I'd like to add in a graph to this email but can't seem to figure out how.
def HTML_Email(subject, to, html, files, filename):
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
from os.path import basename
import email
import email.mime.application
# Create message container - the correct MIME type is
multipart/alternative.
msg = MIMEMultipart('mixed')
msg['Subject'] = subject
msg['From'] = "ChicagoGISScripts#mobilitie.com"
msg['To'] = ", ".join(to)
# Record the MIME types of both parts - text/plain and text/html
part2 = MIMEText(html, 'html')
# create PDF attachment
fp=open(files,'rb')
att = email.mime.application.MIMEApplication(fp.read(),_subtype="xlsx")
fp.close()
att.add_header('Content-Disposition','attachment',filename=filename)
# Attach parts into message container.
msg.attach(att)
msg.attach(part2)
# Send the message via local SMTP server.
user = 'ausername'
pwd = 'apassword'
s = smtplib.SMTP('smtp.office365.com',587)
s.ehlo()
s.starttls()
s.ehlo()
s.login(user,pwd)
s.sendmail(msg['From'], to, msg.as_string())
s.quit()
Typically I'll use something like this to go along with it, but I'm trying to include a .png that's stored locally on my computer. is not working to embed an image into the body of the email, what am I missing here?
html = """\
<html>
<head></head>
<body>
<p><font face ="Gotham, monospace">Some HTML,<br><br>
<img src="C:\\Users\\Me\\Desktop\\graphs.png"></img></font>
</p>
</body>
</html>
"""
Because you aren't hosting the image on a server, you won't be able to embed it in an email using a normal link. Try encoding the .png file into a data uri and setting that as the src
EDIT
Look at this other answer to see how to do this in python
EDIT 2
The resulting html should look like this
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==" alt="Red dot" />
Exactly what RemedialBear said. You have to host the email on a server and have an absolute src in your email body.
Instead of:
<img src="C:\\Users\\Me\\Desktop\\graphs.png">
You need:
<img src="http://www.somedomain.com/images/graphs.png" alt="Name' />