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
Related
I can send the plain text but unable to send html text in html format.
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
body = """
this is first mail by using python
"""
port_email = 587
smtp_server = "smtp.gmail.com"
password = "your password"
subject = "An email with attachment from Python"
sender_email = "sender#gmail.example.com"
receiver_email = "receiver#example.net"
# Create a multipart message and set headers
message = MIMEMultipart()
message["From"] = sender_email
message["To"] = receiver_email
message["Subject"] = subject
message["Bcc"] = receiver_email # Recommended for mass emails
# Add body to email
message.attach(MIMEText(body, "plain"))
filename = "file name" # In same directory as script
with open(filename.html, 'r', encoding="utf-8") as attachment:
part1 = attachment.read()
part2 = MIMEText(part1, "html")
message.attach(part2)
text = message.as_string()
context = ssl.create_default_context()
with smtplib.SMTP_SSL(smtp_server, 465 , context=context) as server:
server.login(sender_email, password)
server.sendmail(sender_email, receiver_email, text)
This will send attach file but i want to see the html text in email body.
filename is content html table so code should send the html text which will automatic available in html body with html table.
Why are you passing a bogus body if that's not what you want?
Your code seems to be written for Python 3.5 or earlier. The email library was overhauled in 3.6 and is now quite a bit more versatile and logical. Probably throw away what you have and start over with the examples from the email documentation.
Here's a brief attempt.
from email.message import EmailMessage
...
message = EmailMessage()
message["From"] = sender_email
message["To"] = receiver_email
message["Subject"] = subject
# No point in using Bcc if the recipient is already in To:
with open(filename) as fp:
message.set_content(fp.read(), 'html')
# no need for a context if you are just using the default SSL
with smtplib.SMTP_SSL(smtp_server, 465) as server:
server.login(sender_email, password)
# Prefer the modern send_message method
server.send_message(message)
If you want to send a message in both plain text and HTML, the linked examples show you how to adapt the code to do that, but then really, the text/plain body part should actually contain a useful message, not just a placeholder.
As commented in the code, there is no reason to use Bcc: if you have already specified the recipient in the To: header. If you want to use Bcc: you will have to put something else in the To: header, commonly your own address or an address list like :undisclosed-recipients;
Tangentially, when opening a file, Python (or in fact the operating system) examines the user's current working directory, not the directory from which the Python script was loaded. Perhaps see also What exactly is current working directory?
Mime has a variety of formats. By default MIMEMultipart builds a multipart/mixed message, meaning a simple text body and a bunch of attachments.
When you want an HTML representation of the body, you want a multipart/alternative message:
...
message = MIMEMultipart('alternative')
...
But you are using the old compat32 API. Since Python 3.6 you'd better use email.message.EmailMessage...
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!')
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)
I want to send an email with attachment (for example a text file) with python. Is this possible with the stdlib or do I have to download and install other packages?
I would like to do this with the stdlib.
thx. :)
You can try this:
# Import smtplib for the actual sending function
import smtplib
# Import the email modules we'll need
from email.mime.text import MIMEText
# Open a plain text file for reading. For this example, assume that
# the text file contains only ASCII characters.
fp = open(textfile, 'rb')
# Create a text/plain message
msg = MIMEText(fp.read())
fp.close()
# me == the sender's email address
# you == the recipient's email address
msg['Subject'] = 'The contents of %s' % textfile
msg['From'] = me
msg['To'] = you
# Send the message via our own SMTP server.
s = smtplib.SMTP('localhost')
s.send_message(msg)
s.quit()
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!