How can I embed an image into an email message? - python

and thanks in advance for helping out. I've been trying to embed an image on this specific code. I've followed some other posts related to this but the result hasn't shown the image displayed when the email is opened. It just shows it as an attachment. Any guidance will be more than helpful. Thanks again!
import email, smtplib, ssl
import os
from email import encoders
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
#body = """ Attached are your results!
#Feel free to reply to this message if you have any questions.
# We look forward to working with you soon.
# Thank you for using Weckrogrid-20! """
sender_email = "WeckroGrid-20"
receiver_email = "*****#gmail.com"
# Create a multipart message and set headers
message = MIMEMultipart()
message["From"] = 'WeckroGrid-20'
#message["To"] = '*****#gmail.com'
message["Subject"] = 'Your Microgrid Plan is here!'
#message["Bcc"] = 'receiver_email' # Recommended for mass emails
# Add body to email
#message.attach(MIMEText(body, "plain"))
filename = "dummy.pdf" # In same directory as script
# Open PDF file in binary mode
with open(filename, "rb") as attachment:
# Add file as application/octet-stream
# Email client can usually download this automatically as attachment
part = MIMEBase("application", "octet-stream")
part.set_payload(attachment.read())
# Encode file in ASCII characters to send by email
encoders.encode_base64(part)
# Add header as key/value pair to attachment part
part.add_header(
"Content-Disposition",
f"attachment; filename= {filename}",
)
#Add attachment to message and convert message to string
message.attach(part)
text = message.as_string('')
# Log in to server using secure context and send email
context = ssl.create_default_context()
with smtplib.SMTP_SSL("smtp.gmail.com", 465, context=context) as server:
server.login('******#gmail.com', '*******')
server.sendmail(sender_email, receiver_email, text)

Related

How to automatically send personalized emails with a pdf attachment in Python?

I am a beginner programmer and I am trying to write a program that automatically sends personalized emails to a list of receivers in a csv file with a pdf attachment.
My current code sends personalized emails but I don't know how to add an attachment. Also, I think it's best practice to write the program in a function but I don't know how to do that either.
It would be greatly appreciated if anyone could help me out. Also, I want to keep it as simple as possible so that I still understand what every line of code does.
import os
import smtplib, ssl
import csv
# Sender credentials (from environment variables)
email_address = os.environ.get("email_user")
email_pass = os.environ.get("email_app_pass")
context = ssl.create_default_context()
with smtplib.SMTP_SSL("smtp.gmail.com", 465, context=context) as server:
server.login(email_address, email_pass) # Log into sender email account
# Email information
subject = "Testing Python Automation"
body = """ Hi {name},\n\n This email was entirely generated in Python. So cool!
"""
msg = f"Subject: {subject}\n\n{body}"
with open("contacts_test.csv") as file:
reader = csv.reader(file)
next(reader) # Skip header row
for name, email in reader:
server.sendmail(email_address, email, msg.format(name=name))
file.close()
server.quit()
This will only work using gmail and make sure you have manually set up
special permissions on your gmail account for the program to be able to send email on behalf of you. The process is described here.
You can use other email address services for that you need to change the smtp server address and the smtp port number in line 32 accordingly and take care of any other additional steps required.
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
body = """
Hi {name},\n\n This email was entirely generated in Python. So cool!
""".format(name="Name")
# details
sender = 'example1#gmail.com' # my email
password = '&*password.$' # my email's password
receiver = 'example2#gmail.com' # receiver's email
msg = MIMEMultipart()
msg['To'] = receiver
msg['From'] = sender
msg['Subject'] = 'Testing Python Automation'
msg.attach(MIMEText(body, 'plain'))
pdfname = "mypdf.pdf" # pdf file name
binary_pdf = open(pdfname, 'rb')
payload = MIMEBase('application', 'octate-stream', Name=pdfname)
payload.set_payload((binary_pdf).read())
encoders.encode_base64(payload)
payload.add_header('Content-Decomposition', 'attachment', filename=pdfname)
msg.attach(payload)
session = smtplib.SMTP('smtp.gmail.com', 587)
session.starttls()
session.login(sender, password)
text = msg.as_string()
session.sendmail(sender, receiver, text)
session.quit()
print('[#] Mail Sent!')

Adding a picture at the bottom of the mail content when sending e-mail with Python SMTP

Using the email and smtp libraries, I have developed a script that automatically sends mail via outlook's smtp server.
I enter the content of the mail and after the content is written I want to send the picture at the bottom.
But it sends the picture not at the bottom as I want it, but at the top of the mail content.
Example mail ( This is only image ) : https://ibb.co/d5HFwRG
My code:
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email.mime.image import MIMEImage
def send_mail(gender, messages, subject):
global msg
try:
msg = MIMEMultipart()
s = smtplib.SMTP(host="SMTP.office365.com", port=587)
s.starttls()
s.login(mail, password)
msg['From'] = mail
msg['To'] = example#outlook.com
msg['Subject'] = messages
msg.attach(MIMEText(message, 'plain', 'utf-8'))
attachment = open("image.jpg", "rb")
p = MIMEBase('application', 'octet-stream')
p.set_payload((attachment).read())
encoders.encode_base64(p)
p.add_header('Content-Disposition', "attachment; filename= %s" % image)
msg.attach(p)
s.send_message(msg)
del msg
except Exception as e:
print(e)
My code is actually much more complex, but I just showed you the function I use to send mail.
I had to change the names of some variables while adding them here, so the above code may not work for you, you need to edit it.
How can I get that picture sent in the Mail to the bottom?

Python: sending mail via python creates unknown attachment

I'm trying to send a mail + attachment (.pdf file) via python.
The mail is send but the attachment becomes an unknown attachment instead of being a .pdf file
My code looks like this:
import smtplib
import os
import ssl
import email
from email import encoders
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
port = 465
smtp_server = "smtp.gmail.com"
subject = "An example of txt.file"
sender = "..."
receiver = "..."
password = "..."
message = MIMEMultipart()
message["From"] = sender
message["To"] = receiver
message["Subject"] = subject
filename = '318.pdf'
attachment = open(filename, "rb")
part = MIMEBase("application", "octet-stream")
part.set_payload(attachment.read())
part.add_header('Content Disposition', 'attachment', filename=filename)
encoders.encode_base64(part)
message.attach(part)
message.attach(part)
body = "This is an example of how to send an email with an .pdf-attachment."
message.attach(MIMEText(body, 'plain'))
text = message.as_string()
context = ssl.create_default_context()
with smtplib.SMTP_SSL("smtp.gmail.com", port, context=context) as server:
server.login(sender, password)
server.sendmail(sender, receiver, text)
print('Sent')
What is wrong with it or what do I have to do differently?
I've tried different file types, the .pdf file is in the python file directory,...
You wrote
part.add_header('Content Disposition', 'attachment', filename=filename)
But the 'filename' argument-name must be provided as a string and you also missed the hyphen in 'Content-Disposition'. Try
part.add_header('Content-Disposition', 'attachment; filename=' + filename)
This should solve your issue. Just pointing out, you attached 'part' twice - on lines 20 and 22.
I think you might already be following this article. But if not, I think you'll find it useful.

Thunderbird "size unknown" attachment when sent with python

When I sent email with an attachment using python code below, although the attachment can be downloaded, it will say size unknown next to the attachment, and if I forward that email, the attachment is not in forwarding email, This seemed to be a problem specific to Thunderbird(60.5.2 (32-bit)), but since our company is entirely on TB, I'll need to fix the python code to make it compatible with TB.
I have played with the raw string of the source from "view source" in TB by comparing the source of a email attachment sent within TB which would work, but to no avail.
PS: found related bug tracker in mozilla for reference: https://bugzilla.mozilla.org/show_bug.cgi?id=548507
import os
import smtplib
from email.header import Header
from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication
from email.mime.text import MIMEText
from email.utils import formataddr
from email.utils import parseaddr
sender = "from#gmail.com"
to_address = ["to#gmail.com"]
subject = "Test subject"
body = "Test body"
title = "title"
attach_files = ['c:\\dummy.pdf']
host = 'localhost.com'
user = 'user#mail.com'
password = 'password'
msg_root = MIMEMultipart('related')
addr = '{} <{}>'.format(title, sender)
name, address = parseaddr(addr)
msg_root['From'] = formataddr((
Header(name, 'utf-8').encode(),
address .encode('utf-8') if isinstance(address , unicode) else address))
msg_root['To'] = ','.join(to_address)
msg_root['Subject'] = Header(subject, 'utf-8')
msg_text = MIMEText(body, 'html', 'utf-8')
msg_root.attach(msg_text)
for index, attach_file in enumerate(attach_files, start=1):
with open(attach_file, 'rb') as attach_obj:
attach = MIMEApplication(attach_obj.read(),
_subtype="pdf",
name=os.path.basename(attach_file))
attach.add_header('Content-Disposition', 'attachment',
filename=os.path.basename(attach_file))
msg_root.attach(attach)
connection = smtplib.SMTP_SSL(host=host, timeout=5)
try:
connection.login(user=user, password=password)
connection.sendmail(user, all_address, msg_root.as_string())
finally:
connection.quit()
I can Accept any answer as long as: when forwarding a email with attachment that's send via Python, the attachment from that email is still included within TB(recent version 60+).
Expected result: a file size next to the attachment, and forwarding the attachment email will also include the attachment.
Use 'mixed' instead of 'related'
msg_root = MIMEMultipart('mixed')
You will see size next to attachement, and attachement will be forwarded.
Tested on TB 60.7.2 (64-bit) / Linux Mint 19.1

Email and smtplib modules in Python - some basic emailing questions

I've just started learning Python and I'm trying to code a bot where it emails a HTML message along with a .docx (Microsoft Word) attachment. Here's my code and it works fine, but I'm confused with a few of the parameters.
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
import os
#Email Variables
myemail = "myemail#hotmail.com"
recipient = "recipientemail#hotmail.com"
#Specifying MIME variables to include in email header
mime_details = MIMEMultipart('mixed')
mime_details['Subject'] = "This is my email subject!"
mime_details['From'] = myemail
mime_details['To'] = recipient
#Creating body of message
html_body = """\
<html>\
<p>\
My email message!
</p>\
</html>\
"""
#Attaching File To Email
os.chdir('C:\\Users\Kyle\Desktop\')
openfile = open('testfile.docx', 'rb')
doc = MIMEApplication(openfile.read(), _subtype='vnd.openxmlformats-officedocument.wordprocessingml.document')
doc.add_header('Content-Disposition', 'attachment', filename='My Content.docx')
mime_details.attach(doc)
openfile.close()
#Recording MIME types of email parts
htmlpart = MIMEText(html_body, _subtype='html')
#Attaching parts to message container
mime_details.attach(htmlpart)
#Sending message via SMTP server
s = smtplib.SMTP(host='smtp.live.com', port=587)
s.ehlo()
s.starttls()
s.login(myemail, 'password')
s.sendmail(myemail, recipient, mime_details.as_string())
s.quit()
I have a few questions regarding the code above, and I would greatly appreciate it if you can help me clear whatever confused thoughts I have regarding the modules above.
A) The add_header module
mime_details['Subject'] = "This is my email subject!"
mime_details['From'] = myemail
mime_details['To'] = recipient
As you can see from the snippet above, I clearly defined each header variable in the MIMEMultipart envelope. According to Python's docs, these values will be added to the header directly. I tried using the add_header() method directly as an alternative, something like:
mime_details.add_header(Subject = "This is my email subject!", To = recipient, From = myemail)
But it gave me errors. Any idea why?
B) At the last few lines of my code, I had to append a .as_string() to the payload I was sending. I tried taking it out but it gave me a TypeError: expected string or buffer.
The Python docs give me this:
as_string(unixfrom=False, maxheaderlen=0, policy=None)
Return the entire message flattened as a string.
I assume that I have to append this in every case? the mime_details object has two parts to it - the HTML message and the .docx file. Both will be converted to strings? What about image files?
C) When I open my file to attach, I read it in 'rb' mode.
Here's the code:
openfile = open('testfile.docx', 'rb')
I tried using 'r' but it raises an error. I've read up on this and 'rb' mode simply opens the file in binary. Why would it make sense to open a .docx file in binary mode? Am I to use 'rb' mode for ALL non.txt files?
D) Finally, I've seen some people use base64 encoding for attachments. I've searched around and a particularly popular script over here is below (from How to send email attachments with Python):
import smtplib, os
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email.mime.text import MIMEText
from email.utils import COMMASPACE, formatdate
from email import encoders
def send_mail( send_from, send_to, subject, text, files=[], server="localhost", port=587, username='', password='', isTls=True):
msg = MIMEMultipart()
msg['From'] = send_from
msg['To'] = COMMASPACE.join(send_to)
msg['Date'] = formatdate(localtime = True)
msg['Subject'] = subject
msg.attach( MIMEText(text) )
for f in files:
part = MIMEBase('application', "octet-stream")
part.set_payload( open(f,"rb").read() )
encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment; filename="{0}"'.format(os.path.basename(f)))
msg.attach(part)
smtp = smtplib.SMTP(server, port)
if isTls: smtp.starttls()
smtp.login(username,password)
smtp.sendmail(send_from, send_to, msg.as_string())
smtp.quit()
Why does content need to be encoded in base64? Does this apply to all files and is a general thing to be added, or can I ignore this? What situations am I to invoke that method?
Finally, being a noob at Python, some of my code above may be redundant\badly structured. If you have any tips\suggestions on how I can improve my simply script, please do let me know.
Thank you!

Categories