Related
I am having problems understanding how to email an attachment using Python. I have successfully emailed simple messages with the smtplib. Could someone please explain how to send an attachment in an email. I know there are other posts online but as a Python beginner I find them hard to understand.
Here's another:
import smtplib
from os.path import basename
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.utils import COMMASPACE, formatdate
def send_mail(send_from, send_to, subject, text, files=None,
server="127.0.0.1"):
assert isinstance(send_to, list)
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 or []:
with open(f, "rb") as fil:
part = MIMEApplication(
fil.read(),
Name=basename(f)
)
# After the file is closed
part['Content-Disposition'] = 'attachment; filename="%s"' % basename(f)
msg.attach(part)
smtp = smtplib.SMTP(server)
smtp.sendmail(send_from, send_to, msg.as_string())
smtp.close()
It's much the same as the first example... But it should be easier to drop in.
Here is the modified version from Oli for python 3
import smtplib
from pathlib import Path
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, message, files=[],
server="localhost", port=587, username='', password='',
use_tls=True):
"""Compose and send email with provided info and attachments.
Args:
send_from (str): from name
send_to (list[str]): to name(s)
subject (str): message title
message (str): message body
files (list[str]): list of file paths to be attached to email
server (str): mail server host name
port (int): port number
username (str): server auth username
password (str): server auth password
use_tls (bool): use TLS mode
"""
msg = MIMEMultipart()
msg['From'] = send_from
msg['To'] = COMMASPACE.join(send_to)
msg['Date'] = formatdate(localtime=True)
msg['Subject'] = subject
msg.attach(MIMEText(message))
for path in files:
part = MIMEBase('application', "octet-stream")
with open(path, 'rb') as file:
part.set_payload(file.read())
encoders.encode_base64(part)
part.add_header('Content-Disposition',
'attachment; filename={}'.format(Path(path).name))
msg.attach(part)
smtp = smtplib.SMTP(server, port)
if use_tls:
smtp.starttls()
smtp.login(username, password)
smtp.sendmail(send_from, send_to, msg.as_string())
smtp.quit()
This is the code I ended up using:
import smtplib
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email import Encoders
SUBJECT = "Email Data"
msg = MIMEMultipart()
msg['Subject'] = SUBJECT
msg['From'] = self.EMAIL_FROM
msg['To'] = ', '.join(self.EMAIL_TO)
part = MIMEBase('application', "octet-stream")
part.set_payload(open("text.txt", "rb").read())
Encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment; filename="text.txt"')
msg.attach(part)
server = smtplib.SMTP(self.EMAIL_SERVER)
server.sendmail(self.EMAIL_FROM, self.EMAIL_TO, msg.as_string())
Code is much the same as Oli's post.
Code based from Binary file email attachment problem post.
from email.MIMEMultipart import MIMEMultipart
from email.MIMEText import MIMEText
from email.MIMEImage import MIMEImage
import smtplib
msg = MIMEMultipart()
msg.attach(MIMEText(file("text.txt").read()))
msg.attach(MIMEImage(file("image.png").read()))
# to send
mailer = smtplib.SMTP()
mailer.connect()
mailer.sendmail(from_, to, msg.as_string())
mailer.close()
Adapted from here.
Gmail version, working with Python 3.6 (note that you will need to change your Gmail settings to be able to send email via smtp from it:
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication
from os.path import basename
def send_mail(send_from: str, subject: str, text: str,
send_to: list, files= None):
send_to= default_address if not send_to else send_to
msg = MIMEMultipart()
msg['From'] = send_from
msg['To'] = ', '.join(send_to)
msg['Subject'] = subject
msg.attach(MIMEText(text))
for f in files or []:
with open(f, "rb") as fil:
ext = f.split('.')[-1:]
attachedfile = MIMEApplication(fil.read(), _subtype = ext)
attachedfile.add_header(
'content-disposition', 'attachment', filename=basename(f) )
msg.attach(attachedfile)
smtp = smtplib.SMTP(host="smtp.gmail.com", port= 587)
smtp.starttls()
smtp.login(username,password)
smtp.sendmail(send_from, send_to, msg.as_string())
smtp.close()
Usage:
username = 'my-address#gmail.com'
password = 'top-secret'
default_address = ['my-address2#gmail.com']
send_mail(send_from= username,
subject="test",
text="text",
send_to= None,
files= # pass a list with the full filepaths here...
)
To use with any other email provider, just change the smtp configurations.
Another way with python 3 (If someone is searching):
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
fromaddr = "sender mail address"
toaddr = "receiver mail address"
msg = MIMEMultipart()
msg['From'] = fromaddr
msg['To'] = toaddr
msg['Subject'] = "SUBJECT OF THE EMAIL"
body = "TEXT YOU WANT TO SEND"
msg.attach(MIMEText(body, 'plain'))
filename = "fileName"
attachment = open("path of file", "rb")
part = MIMEBase('application', 'octet-stream')
part.set_payload((attachment).read())
encoders.encode_base64(part)
part.add_header('Content-Disposition', "attachment; filename= %s" % filename)
msg.attach(part)
server = smtplib.SMTP('smtp.gmail.com', 587)
server.starttls()
server.login(fromaddr, "sender mail password")
text = msg.as_string()
server.sendmail(fromaddr, toaddr, text)
server.quit()
Make sure to allow “less secure apps” on your Gmail account
Because there are many answers here for Python 3, but none which show how to use the overhauled email library from Python 3.6, here is a quick copy+paste from the current email examples documentation.
(I have abridged it somewhat to remove frills like guessing the correct MIME type.)
Modern code which targets Python >3.5 should no longer use the email.message.Message API (including the various MIMEText, MIMEMultipart, MIMEBase etc classes) or the even older mimetypes mumbo jumbo.
from email.message import EmailMessage
import smtplib
msg = EmailMessage()
msg["Subject"] = "Our family reunion"
msg["From"] = "me <sender#example.org>"
msg["To"] = "recipient <victim#example.net>"
# definitely don't mess with the .preamble
msg.set_content("Hello, victim! Look at these pictures")
with open("path/to/attachment.png", "rb") as fp:
msg.add_attachment(
fp.read(), maintype="image", subtype="png")
# Notice how smtplib now includes a send_message() method
with smtplib.SMTP("localhost") as s:
s.send_message(msg)
The modern email.message.EmailMessage API is now quite a bit more versatile and logical than the older version of the library. There are still a few kinks around the presentation in the documentation (it's not obvious how to change the Content-Disposition: of an attachment, for example; and the discussion of the policy module is probably too obscure for most newcomers) and fundamentally, you still need to have some sort of idea of what the MIME structure should look like (though the library now finally takes care of a lot of the nitty-gritty around that). Perhaps see What are the "parts" in a multipart email? for a brief introduction.
Using localhost as your SMTP server obviously only works if you actually have an SMTP server running on your local computer. Properly getting email off your system is a fairly complex separate question. For simple requirements, probably use your existing email account and your provider's email server (search for examples of using port 587 with Google, Yahoo, or whatever you have - what exactly works depends somewhat on the provider; some will only support port 465, or legacy port 25 which is however now by and large impossible to use on public-facing servers because of spam filtering).
The simplest code I could get to is:
#for attachment email
from django.core.mail import EmailMessage
def attachment_email(request):
email = EmailMessage(
'Hello', #subject
'Body goes here', #body
'MyEmail#MyEmail.com', #from
['SendTo#SendTo.com'], #to
['bcc#example.com'], #bcc
reply_to=['other#example.com'],
headers={'Message-ID': 'foo'},
)
email.attach_file('/my/path/file')
email.send()
It was based on the official Django documentation
Other answers are excellent, though I still wanted to share a different approach in case someone is looking for alternatives.
Main difference here is that using this approach you can use HTML/CSS to format your message, so you can get creative and give some styling to your email. Though you aren't enforced to use HTML, you can also still use only plain text.
Notice that this function accepts sending the email to multiple recipients and also allows to attach multiple files.
I've only tried this on Python 2, but I think it should work fine on 3 as well:
import os.path
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
def send_email(subject, message, from_email, to_email=[], attachment=[]):
"""
:param subject: email subject
:param message: Body content of the email (string), can be HTML/CSS or plain text
:param from_email: Email address from where the email is sent
:param to_email: List of email recipients, example: ["a#a.com", "b#b.com"]
:param attachment: List of attachments, exmaple: ["file1.txt", "file2.txt"]
"""
msg = MIMEMultipart()
msg['Subject'] = subject
msg['From'] = from_email
msg['To'] = ", ".join(to_email)
msg.attach(MIMEText(message, 'html'))
for f in attachment:
with open(f, 'rb') as a_file:
basename = os.path.basename(f)
part = MIMEApplication(a_file.read(), Name=basename)
part['Content-Disposition'] = 'attachment; filename="%s"' % basename
msg.attach(part)
email = smtplib.SMTP('your-smtp-host-name.com')
email.sendmail(from_email, to_email, msg.as_string())
I hope this helps! :-)
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
import smtplib
import mimetypes
import email.mime.application
smtp_ssl_host = 'smtp.gmail.com' # smtp.mail.yahoo.com
smtp_ssl_port = 465
s = smtplib.SMTP_SSL(smtp_ssl_host, smtp_ssl_port)
s.login(email_user, email_pass)
msg = MIMEMultipart()
msg['Subject'] = 'I have a picture'
msg['From'] = email_user
msg['To'] = email_user
txt = MIMEText('I just bought a new camera.')
msg.attach(txt)
filename = 'introduction-to-algorithms-3rd-edition-sep-2010.pdf' #path to file
fo=open(filename,'rb')
attach = email.mime.application.MIMEApplication(fo.read(),_subtype="pdf")
fo.close()
attach.add_header('Content-Disposition','attachment',filename=filename)
msg.attach(attach)
s.send_message(msg)
s.quit()
For explanation, you can use this link it explains properly
https://medium.com/#sdoshi579/to-send-an-email-along-with-attachment-using-smtp-7852e77623
from email.mime.multipart import MIMEMultipart
from email.mime.image import MIMEImage
from email.mime.text import MIMEText
import smtplib
msg = MIMEMultipart()
password = "password"
msg['From'] = "from_address"
msg['To'] = "to_address"
msg['Subject'] = "Attached Photo"
msg.attach(MIMEImage(file("abc.jpg").read()))
file = "file path"
fp = open(file, 'rb')
img = MIMEImage(fp.read())
fp.close()
msg.attach(img)
server = smtplib.SMTP('smtp.gmail.com: 587')
server.starttls()
server.login(msg['From'], password)
server.sendmail(msg['From'], msg['To'], msg.as_string())
server.quit()
I know this is an old question but I thought there must be an easier way of doing this than the other examples, thus I made a library that solves this cleanly without polluting your codebase. Including attachments is super easy:
from redmail import EmailSender
from pathlib import Path
# Configure an email sender
email = EmailSender(
host="<SMTP HOST>", port=0,
user_name="me#example.com", password="<PASSWORD>"
)
# Send an email
email.send(
sender="me#example.com",
receivers=["you#example.com"],
subject="An example email"
attachments={
"myfile.txt": Path("path/to/a_file.txt"),
"myfile.html": "<h1>Content of a HTML attachment</h1>"
}
)
You may also directly attach bytes, a Pandas DataFrame (which is converted to format depending on file extension in the key), a Matplotlib Figure or a Pillow Image. The library is most likely all the features you need for an email sender (has a lot more than attachments).
To install:
pip install redmail
Use it any way you like. I also wrote extensive documentation: https://red-mail.readthedocs.io/en/latest/
None of the currently given answers here will work correctly with non-ASCII symbols in filenames with clients like GMail, Outlook 2016, and others that don't support RFC 2231 (e.g., see here). The Python 3 code below is adapted from some other stackoverflow answers (sorry, didn't save the origin links) and odoo/openerp code for Python 2.7 (see ir_mail_server.py). It works correctly with GMail and others, and also uses SSL.
import smtplib, ssl
from os.path import basename
from email.mime.base import MIMEBase
from mimetypes import guess_type
from email.encoders import encode_base64
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.utils import COMMASPACE, formatdate
from email.charset import Charset
def try_coerce_ascii(string_utf8):
"""Attempts to decode the given utf8-encoded string
as ASCII after coercing it to UTF-8, then return
the confirmed 7-bit ASCII string.
If the process fails (because the string
contains non-ASCII characters) returns ``None``.
"""
try:
string_utf8.encode('ascii')
except UnicodeEncodeError:
return
return string_utf8
def encode_header_param(param_text):
"""Returns an appropriate RFC 2047 encoded representation of the given
header parameter value, suitable for direct assignation as the
param value (e.g. via Message.set_param() or Message.add_header())
RFC 2822 assumes that headers contain only 7-bit characters,
so we ensure it is the case, using RFC 2047 encoding when needed.
:param param_text: unicode or utf-8 encoded string with header value
:rtype: string
:return: if ``param_text`` represents a plain ASCII string,
return the same 7-bit string, otherwise returns an
ASCII string containing the RFC2047 encoded text.
"""
if not param_text: return ""
param_text_ascii = try_coerce_ascii(param_text)
return param_text_ascii if param_text_ascii\
else Charset('utf8').header_encode(param_text)
smtp_server = '<someserver.com>'
smtp_port = 465 # Default port for SSL
sender_email = '<sender_email#some.com>'
sender_password = '<PASSWORD>'
receiver_emails = ['<receiver_email_1#some.com>', '<receiver_email_2#some.com>']
subject = 'Test message'
message = """\
Hello! This is a test message with attachments.
This message is sent from Python."""
files = ['<path1>/файл1.pdf', '<path2>/файл2.png']
# Create a secure SSL context
context = ssl.create_default_context()
msg = MIMEMultipart()
msg['From'] = sender_email
msg['To'] = COMMASPACE.join(receiver_emails)
msg['Date'] = formatdate(localtime=True)
msg['Subject'] = subject
msg.attach(MIMEText(message))
for f in files:
mimetype, _ = guess_type(f)
mimetype = mimetype.split('/', 1)
with open(f, "rb") as fil:
part = MIMEBase(mimetype[0], mimetype[1])
part.set_payload(fil.read())
encode_base64(part)
filename_rfc2047 = encode_header_param(basename(f))
# The default RFC 2231 encoding of Message.add_header() works in Thunderbird but not GMail
# so we fix it by using RFC 2047 encoding for the filename instead.
part.set_param('name', filename_rfc2047)
part.add_header('Content-Disposition', 'attachment', filename=filename_rfc2047)
msg.attach(part)
with smtplib.SMTP_SSL(smtp_server, smtp_port, context=context) as server:
server.login(sender_email, sender_password)
server.sendmail(sender_email, receiver_emails, msg.as_string())
Here is an updated version for Python 3.6 and newer using the EmailMessage class of the overhauled email module in the Python standard library.
import mimetypes
import os
import smtplib
from email.message import EmailMessage
username = "user#example.com"
password = "password"
smtp_url = "smtp.example.com"
port = 587
def send_mail(subject: str, send_from: str, send_to: str, message: str, directory: str, filename: str):
# Create the email message
msg = EmailMessage()
msg['Subject'] = subject
msg['From'] = send_from
msg['To'] = send_to
# Set email content
msg.set_content(message)
path = directory + filename
if os.path.exists(path):
ctype, encoding = mimetypes.guess_type(path)
if ctype is None or encoding is not None:
# No guess could be made, or the file is encoded (compressed), so
# use a generic bag-of-bits type.
ctype = 'application/octet-stream'
maintype, subtype = ctype.split('/', 1)
# Add email attachment
with open(path, 'rb') as fp:
msg.add_attachment(fp.read(),
maintype=maintype,
subtype=subtype,
filename=filename)
smtp = smtplib.SMTP(smtp_url, port)
smtp.starttls() # for using port 587
smtp.login(username, password)
smtp.send_message(msg)
smtp.quit()
You can find more examples here.
Below is combination of what I've found from SoccerPlayer's post Here and the following link that made it easier for me to attach an xlsx file. Found Here
file = 'File.xlsx'
username=''
password=''
send_from = ''
send_to = 'recipient1 , recipient2'
Cc = 'recipient'
msg = MIMEMultipart()
msg['From'] = send_from
msg['To'] = send_to
msg['Cc'] = Cc
msg['Date'] = formatdate(localtime = True)
msg['Subject'] = ''
server = smtplib.SMTP('smtp.gmail.com')
port = '587'
fp = open(file, 'rb')
part = MIMEBase('application','vnd.ms-excel')
part.set_payload(fp.read())
fp.close()
encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment', filename='Name File Here')
msg.attach(part)
smtp = smtplib.SMTP('smtp.gmail.com')
smtp.ehlo()
smtp.starttls()
smtp.login(username,password)
smtp.sendmail(send_from, send_to.split(',') + msg['Cc'].split(','), msg.as_string())
smtp.quit()
You can also specify the type of attachment you want in your e-mail, as an example I used pdf:
def send_email_pdf_figs(path_to_pdf, subject, message, destination, password_path=None):
## credits: http://linuxcursor.com/python-programming/06-how-to-send-pdf-ppt-attachment-with-html-body-in-python-script
from socket import gethostname
#import email
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import smtplib
import json
server = smtplib.SMTP('smtp.gmail.com', 587)
server.starttls()
with open(password_path) as f:
config = json.load(f)
server.login('me#gmail.com', config['password'])
# Craft message (obj)
msg = MIMEMultipart()
message = f'{message}\nSend from Hostname: {gethostname()}'
msg['Subject'] = subject
msg['From'] = 'me#gmail.com'
msg['To'] = destination
# Insert the text to the msg going by e-mail
msg.attach(MIMEText(message, "plain"))
# Attach the pdf to the msg going by e-mail
with open(path_to_pdf, "rb") as f:
#attach = email.mime.application.MIMEApplication(f.read(),_subtype="pdf")
attach = MIMEApplication(f.read(),_subtype="pdf")
attach.add_header('Content-Disposition','attachment',filename=str(path_to_pdf))
msg.attach(attach)
# send msg
server.send_message(msg)
inspirations/credits to: http://linuxcursor.com/python-programming/06-how-to-send-pdf-ppt-attachment-with-html-body-in-python-script
Try This i hope this might help
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
fromaddr = "youremailhere"
toaddr = input("Enter The Email Adress You want to send to: ")
# instance of MIMEMultipart
msg = MIMEMultipart()
# storing the senders email address
msg['From'] = fromaddr
# storing the receivers email address
msg['To'] = toaddr
# storing the subject
msg['Subject'] = input("What is the Subject:\t")
# string to store the body of the mail
body = input("What is the body:\t")
# attach the body with the msg instance
msg.attach(MIMEText(body, 'plain'))
# open the file to be sent
filename = input("filename:")
attachment = open(filename, "rb")
# instance of MIMEBase and named as p
p = MIMEBase('application', 'octet-stream')
# To change the payload into encoded form
p.set_payload((attachment).read())
# encode into base64
encoders.encode_base64(p)
p.add_header('Content-Disposition', "attachment; filename= %s" % filename)
# attach the instance 'p' to instance 'msg'
msg.attach(p)
# creates SMTP session
s = smtplib.SMTP('smtp.gmail.com', 587)
# start TLS for security
s.starttls()
# Authentication
s.login(fromaddr, "yourpaswordhere)
# Converts the Multipart msg into a string
text = msg.as_string()
# sending the mail
s.sendmail(fromaddr, toaddr, text)
# terminating the session
s.quit()
Had a bit of a hussle in getting my script to send generic attachments but after a bit of work doing research and skimming through articles on this post, I finally came up with the following
# to query:
import sys
import ast
from datetime import datetime
import smtplib
import mimetypes
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from email import encoders
from email.message import Message
from email.mime.audio import MIMEAudio
from email.mime.base import MIMEBase
from email.mime.image import MIMEImage
from email.mime.text import MIMEText
from dotenv import load_dotenv, dotenv_values
load_dotenv() # load environment variables from .env
'''
sample .env file
# .env file
SECRET_KEY="gnhfpsjxxxxxxxx"
DOMAIN="GMAIL"
TOP_LEVEL_DOMAIN="COM"
EMAIL="CHESERExxxxxx#${DOMAIN}.${TOP_LEVEL_DOMAIN}"
TO_ADDRESS = ("cheseremxxxxx#gmail.com","cheserek#gmail.com")#didn't use this in the code but you can load recipients from here
'''
import smtplib
tls_port = 587
ssl_port = 465
smtp_server_domain_names = {'GMAIL': ('smtp.gmail.com', tls_port, ssl_port),
'OUTLOOK': ('smtp-mail.outlook.com', tls_port, ssl_port),
'YAHOO': ('smtp.mail.yahoo.com', tls_port, ssl_port),
'AT&T': ('smtp.mail.att.net', tls_port, ssl_port),
}
# todo: Ability to choose mail server provider
# auto read in from the dictionary the respective mail server address and the tls and ssl ports
class Bimail:
def __init__(self, subject, recipients):
self.subject = subject
self.recipients = recipients
self.htmlbody = ''
self.mail_username = 'will be loaded from .env file'
self.mail_password = 'loaded from .env file as well'
self.attachments = []
# Creating an smtp object
# todo: if gmail passed in use gmail's dictionary values
def setup_mail_client(self, domain_key_to_use="GMAIL",
email_servers_domains_dict=smtp_server_domain_names):
"""
:param report_pdf:
:type to_address: str
"""
smtpObj = None
encryption_status = True
config = dotenv_values(".env")
# check if the domain_key exists from within the available email-servers-domains dict file passed in
# else throw an error
# read environment file to get the Domain to be used
if f"{domain_key_to_use}" in email_servers_domains_dict.keys():
# if the key is found do the following
# 1.extract the domain,tls,ssl ports from email_servers dict for use in program
try:
values_tuple = email_servers_domains_dict.get(f"{domain_key_to_use}")
ssl_port = values_tuple[2]
tls_port = values_tuple[1]
smtp_server = values_tuple[0]
smtpObj = smtplib.SMTP(smtp_server, tls_port)
print(f"Success connect with tls on {tls_port}")
print('Awaiting for connection encryption via startttls()')
encryption_status = False
except:
print(f"Failed connection via tls on port {tls_port}")
try:
smtpObj = smtplib.SMTP_SSL(smtp_server, ssl_port)
print(f"Success connect with ssl on {ssl_port}")
encryption_status = True
except:
print(f"Failed connection via ssl on port {ssl_port}")
finally:
print("Within Finally block")
if not smtpObj:
print("Failed!!! no Internet connection")
else:
# if connection channel is unencrypted via the use of tls encrypt it
if not encryption_status:
status = smtpObj.starttls()
if status[0] == 220:
print("Successfully Encrypted tls channel")
print("Successfully Connected!!!! Requesting Login")
# Loading .env file values to config variable
#load Login Creds from ENV File
self.mail_username = f'{config.get("EMAIL")}'
self.mail_password = f'{cofig.get("SECRET_KEY")}'
status = smtpObj.login(self.mail_usernam,self.mail_password)
if status[0] == 235:
print("Successfully Authenticated User to xxx account")
success = self.send(smtpObj, f'{config.get("EMAIL")}')
if not bool(success):
print(f"Success in Sending Mail to {success}")
print("Disconnecting from Server INstance")
quit_result = smtpObj.quit()
else:
print(f"Failed to Post {success}!!!")
print(f"Quiting anyway !!!")
quit_result = smtpObj.quit()
else:
print("Application Specific Password is Required")
else:
print("World")
def send(self,smtpObj,from_address):
msg = MIMEMultipart('alternative')
msg['From'] = from_address
msg['Subject'] = self.subject
msg['To'] = ", ".join(self.recipients) # to must be array of the form ['mailsender135#gmail.com']
msg.preamble = "preamble goes here"
# check if there are attachments if yes, add them
if self.attachments:
self.attach(msg)
# add html body after attachments
msg.attach(MIMEText(self.htmlbody, 'html'))
# send
print(f"Attempting Email send to the following addresses {self.recipients}")
result = smtpObj.sendmail(from_address, self.recipients,msg.as_string())
return result
def htmladd(self, html):
self.htmlbody = self.htmlbody + '<p></p>' + html
def attach(self, msg):
for f in self.attachments:
ctype, encoding = mimetypes.guess_type(f)
if ctype is None or encoding is not None:
ctype = "application/octet-stream"
maintype, subtype = ctype.split("/", 1)
if maintype == "text":
fp = open(f)
# Note: we should handle calculating the charset
attachment = MIMEText(fp.read(), _subtype=subtype)
fp.close()
elif maintype == "image":
fp = open(f, "rb")
attachment = MIMEImage(fp.read(), _subtype=subtype)
fp.close()
elif maintype == "ppt":
fp = open(f, "rb")
attachment = MIMEApplication(fp.read(), _subtype=subtype)
fp.close()
elif maintype == "audio":
fp = open(f, "rb")
attachment = MIMEAudio(fp.read(), _subtype=subtype)
fp.close()
else:
fp = open(f, "rb")
attachment = MIMEBase(maintype, subtype)
attachment.set_payload(fp.read())
fp.close()
encoders.encode_base64(attachment)
attachment.add_header("Content-Disposition", "attachment", filename=f)
attachment.add_header('Content-ID', '<{}>'.format(f))
msg.attach(attachment)
def addattach(self, files):
self.attachments = self.attachments + files
# example below
if __name__ == '__main__':
# subject and recipients
mymail = Bimail('Sales email ' + datetime.now().strftime('%Y/%m/%d'),
['cheseremxx#gmail.com', 'tkemboxxx#gmail.com'])
# start html body. Here we add a greeting.
mymail.htmladd('Good morning, find the daily summary below.')
# Further things added to body are separated by a paragraph, so you do not need to worry about newlines for new sentences
# here we add a line of text and an html table previously stored in the variable
mymail.htmladd('Daily sales')
mymail.addattach(['htmlsalestable.xlsx'])
# another table name + table
mymail.htmladd('Daily bestsellers')
mymail.addattach(['htmlbestsellertable.xlsx'])
# add image chart title
mymail.htmladd('Weekly sales chart')
# attach image chart
mymail.addattach(['saleschartweekly.png'])
# refer to image chart in html
mymail.htmladd('<img src="cid:saleschartweekly.png"/>')
# attach another file
mymail.addattach(['MailSend.py'])
# send!
mymail.setup_mail_client( domain_key_to_use="GMAIL",email_servers_domains_dict=smtp_server_domain_names)
With my code you can send email attachments using gmail you will need to:
Set your gmail address at ___YOUR SMTP EMAIL HERE___
Set your gmail account password at __YOUR SMTP PASSWORD HERE___
In the ___EMAIL TO RECEIVE THE MESSAGE__ part you need to set the destination email address.
Alarm notification is the subject.
Someone has entered the room, picture attached is the body.
["/home/pi/webcam.jpg"] is an image attachment.
Here is the full code:
#!/usr/bin/env python
import smtplib
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email.Utils import COMMASPACE, formatdate
from email import Encoders
import os
USERNAME = "___YOUR SMTP EMAIL HERE___"
PASSWORD = "__YOUR SMTP PASSWORD HERE___"
def sendMail(to, subject, text, files=[]):
assert type(to)==list
assert type(files)==list
msg = MIMEMultipart()
msg['From'] = USERNAME
msg['To'] = COMMASPACE.join(to)
msg['Date'] = formatdate(localtime=True)
msg['Subject'] = subject
msg.attach( MIMEText(text) )
for file in files:
part = MIMEBase('application', "octet-stream")
part.set_payload( open(file,"rb").read() )
Encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment; filename="%s"'
% os.path.basename(file))
msg.attach(part)
server = smtplib.SMTP('smtp.gmail.com:587')
server.ehlo_or_helo_if_needed()
server.starttls()
server.ehlo_or_helo_if_needed()
server.login(USERNAME,PASSWORD)
server.sendmail(USERNAME, to, msg.as_string())
server.quit()
sendMail( ["___EMAIL TO RECEIVE THE MESSAGE__"],
"Alarm notification",
"Someone has entered the room, picture attached",
["/home/pi/webcam.jpg"] )
I have to functions send_output_mail which will call process_mail to send mail to the given recipients with multiple attacthments.
Here is my code
import smtplib
from string import Template
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email.mime.text import MIMEText
from email import encoders
import os
import pandas as pd
server = '112.11.1.111'; port = 11
MY_ADDRESS = 'xyz#outlook.com'
from datetime import datetime
def process_email(**kwargs): # accept variable number of keyworded arguments
# get total email recipients
rcpt = []
for email in kwargs['emails']:
for i in email:
rcpt.append(i)
# set up the SMTP server
s = smtplib.SMTP(host=server, port=port)
msg = MIMEMultipart() # create a message
# setup the parameters of the message, to cc emails
msg['From'] = MY_ADDRESS
msg['To'] = ','.join(kwargs['emails'][0])
msg['Cc'] = ','.join(kwargs['emails'][1])
msg['Subject'] = kwargs['subject']
if 'attachments' in kwargs.keys():
for attachment in kwargs['attachments']:
fullpath_attactment = os.path.join(os.getcwd(),"Output_file",attachment) #will give full path of the file
with open(fullpath_attactment) as fp:
record = MIMEBase('application', 'octet-stream')
record.set_payload(fp.read())
encoders.encode_base64(record)
record.add_header('Content-Disposition', 'attachment',
filename=os.path.basename(fullpath_attactment))
msg.attach(record)
s.sendmail(MY_ADDRESS, rcpt, msg.as_string()) **#Getting Error Here**
s.quit()
def send_output_mail():
emails = [["xyz#outlook.com", "hy#outlook.com"], ["xxx#outlook.com","yy#outlook.com"]]
subject = "Reports"
process_email(emails=emails, subject=subject, attachments= ["xx.csv","yy.csv"])
Problem
As i Debugged i am getting smtplib.SMTPDataError: (554, b'5.5.1 Error: no valid recipients') while executing line
s.sendmail(MY_ADDRESS, rcpt, msg.as_string())
I have crosschecked and the mailid that i have written and it was also correct, still getting this error.
I have my mail my_name#company.com and uses gmails API (and python) to send some mails. The problem is that when the mail hit the inbox the "from" is shown as my_name#company.com '<my_name#company.com>' where I want it to be First Name <my_name#company.com>.
I have tried using different variations of "First Name '<my_name#company.com>'" but I get a RefreshError: ('invalid_request: Invalid impersonation "sub" field.', '{\n "error": "invalid_request",\n "error_description": "Invalid impersonation \\u0026quot;sub\\u0026quot; field."\n}').
from __future__ import print_function
from googleapiclient.discovery import build
from apiclient import errors
from httplib2 import Http
from email.mime.text import MIMEText
import base64
from google.oauth2 import service_account
# Email variables. Modify this!
EMAIL_FROM = "First Last '<my_name#company.com>'"
EMAIL_TO = 'some_mail#hotmail.com'
EMAIL_SUBJECT = 'Hello from Me!'
EMAIL_CONTENT = 'Some body'
# Call the Gmail API
def service_account_login():
SCOPES = ['https://www.googleapis.com/auth/gmail.send']
SERVICE_ACCOUNT_FILE = 'my-credentials.json'
credentials = service_account.Credentials.from_service_account_file(
SERVICE_ACCOUNT_FILE, scopes=SCOPES)
delegated_credentials = credentials.with_subject(EMAIL_FROM)
service = build('gmail', 'v1', credentials=delegated_credentials)
return service
def create_message(sender, to, subject, message_text):
message = MIMEText(message_text)
message['to'] = to
message['from'] = sender
message['subject'] = subject
raw = base64.urlsafe_b64encode(message.as_bytes())
raw = raw.decode()
return {"raw": raw}
def send_message(service, user_id, message):
try:
message = (service.users().messages().send(userId=user_id, body=message)
.execute())
print('Message Id: %s' % message['id'])
return message
except errors.HttpError as error:
print('An error occurred: %s' % error)
service = service_account_login()
message = create_message(EMAIL_FROM, EMAIL_TO, EMAIL_SUBJECT, EMAIL_CONTENT)
sent = send_message(service,'me', message)
I just sent an email recently showing the name as you wanted, I got it with this line, similar to what you already had but without the single quotation marks:
message['from'] = "First Name <something#example.com>"
So the trick is fairly simple - the EMAIL_FROM is first used to create a service with that email, which is why you cannot write My Name <my_name#company.com>. You can do that when you need to specify the "FROM " mail e.g in the very buttom of create_message= f"First name<{EMAIL_FROM}>,...)
I am trying to send html e-mails with base64 encoded images embeded in them, using gmail api and python.
This is the html file that I want to send as email
<h1>This is a test message</h1>
<p>
<img src="data:image/png;base64,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">
</p>
Here are my codes
"""Send an email message from the user's account.
"""
import base64
from email.mime.audio import MIMEAudio
from email.mime.base import MIMEBase
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import mimetypes
import os
from apiclient import errors
def send_message(service, user_id, message):
"""Send an email message.
Args:
service: Authorized Gmail API service instance.
user_id: User's email address. The special value "me"
can be used to indicate the authenticated user.
message: Message to be sent.
Returns:
Sent Message.
"""
try:
message = (service.users().messages().send(userId=user_id, body=message)
.execute())
print 'Message Id: %s' % message['id']
return message
except errors.HttpError, error:
print 'An error occurred: %s' % error
def create_message(sender, to, subject, message_text):
"""Create a message for an email.
Args:
sender: Email address of the sender.
to: Email address of the receiver.
subject: The subject of the email message.
message_text: The text of the email message.
Returns:
An object containing a base64url encoded email object.
"""
message = MIMEText(message_text,'html')
message['to'] = to
message['from'] = sender
message['subject'] = subject
return {'raw': base64.urlsafe_b64encode(message.as_string())}
if __name__ == "__main__":
from login import service
with open("test.html","rb") as f:
message_body = f.read()
m = create_message("xxx#gmail.com","xxx#gmail.com","test message",message_body)
send_message(service, "me", m)
However, I don't see my image in the e-mail content. When I inspect the original, I can see that my html is malformed like this;
Content-Type: multipart/alternative; boundary=001a114442124f125f053789c367
--001a114442124f125f053789c367
Content-Type: text/plain; charset=UTF-8
This is a test message
--001a114442124f125f053789c367
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<h1>This is a test message</h1>
<p>
<img src=3D"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAAEsCAMAA=
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3D">
</p>
--001a114442124f125f053789c367--
As you can see, there is a 3D inserted in <img src=3D"data:image/png;base64 ... part.
What is the correct way to embed images in e-mails using gmail api?
Addition
After further investigation, I have realized that if I convert =3D in my e-mail back to =, image is still broken.
I think problem might be related to the fact that my base64 encoded data is splitted into multiple lines in e-mail source code.
Instead of using embed base64 encoding, I decided to add images as attachments. Here is my new test.html file;
<h1>This is a test message</h1>
<p>
<img src="cid:asdfgh">
</p>
And here is my code
"""Send an email message from the user's account.
"""
import base64
from email.mime.audio import MIMEAudio
from email.mime.base import MIMEBase
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import mimetypes
import os
from apiclient import errors
def send_message(service, user_id, message):
"""Send an email message.
Args:
service: Authorized Gmail API service instance.
user_id: User's email address. The special value "me"
can be used to indicate the authenticated user.
message: Message to be sent.
Returns:
Sent Message.
"""
try:
message = (service.users().messages().send(userId=user_id, body=message)
.execute())
print 'Message Id: %s' % message['id']
return message
except errors.HttpError, error:
print 'An error occurred: %s' % error
def create_message(sender, to, subject, message_text):
"""Create a message for an email.
Args:
sender: Email address of the sender.
to: Email address of the receiver.
subject: The subject of the email message.
message_text: The text of the email message.
Returns:
An object containing a base64url encoded email object.
"""
message = MIMEText(message_text,'html')
message['to'] = to
message['from'] = sender
message['subject'] = subject
return {'raw': base64.urlsafe_b64encode(message.as_string())}
def create_multipart_message(sender, to, subject, message_text):
message = MIMEMultipart()
message['to'] = to
message['from'] = sender
message['subject'] = subject
msg = MIMEText(message_text,'html')
message.attach(msg)
return message
def attach_file_to_multipart_message(message, file, content_id=None):
content_type, encoding = mimetypes.guess_type(file)
if content_type is None or encoding is not None:
content_type = 'application/octet-stream'
main_type, sub_type = content_type.split('/', 1)
if main_type == 'text':
fp = open(file, 'rb')
msg = MIMEText(fp.read(), _subtype=sub_type)
fp.close()
elif main_type == 'image':
fp = open(file, 'rb')
msg = MIMEImage(fp.read(), _subtype=sub_type)
fp.close()
elif main_type == 'audio':
fp = open(file, 'rb')
msg = MIMEAudio(fp.read(), _subtype=sub_type)
fp.close()
else:
fp = open(file, 'rb')
msg = MIMEBase(main_type, sub_type)
msg.set_payload(fp.read())
fp.close()
filename = os.path.basename(file)
msg.add_header('Content-Disposition', 'attachment', filename=filename)
if content_id:
msg.add_header('Content-ID', '<%s>' % content_id)
message.attach(msg)
def finalize_message(message):
return {"raw": base64.urlsafe_b64encode(message.as_string())}
if __name__ == "__main__":
from login import service
m = create_multipart_message("xxxx#gmail","xxxx#gmail.com","test message", open("test.html").read())
attach_file_to_multipart_message(m, "placeholder.png", "asdfgh")
m_final = finalize_message(m)
send_message(service, "me", m_final)
Using this method, I was able to show images in my html e-mails.
The "=" character is an escape character when using Quoted-Printable HTML, so the =3D is just an escaped equals.
There is probably something else wrong with the email. I don't think the =3D is it.
Try feeding your message to a message lint utility and see if it complains about anything.
https://tools.ietf.org/tools/msglint/
I am having problems understanding how to email an attachment using Python. I have successfully emailed simple messages with the smtplib. Could someone please explain how to send an attachment in an email. I know there are other posts online but as a Python beginner I find them hard to understand.
Here's another:
import smtplib
from os.path import basename
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.utils import COMMASPACE, formatdate
def send_mail(send_from, send_to, subject, text, files=None,
server="127.0.0.1"):
assert isinstance(send_to, list)
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 or []:
with open(f, "rb") as fil:
part = MIMEApplication(
fil.read(),
Name=basename(f)
)
# After the file is closed
part['Content-Disposition'] = 'attachment; filename="%s"' % basename(f)
msg.attach(part)
smtp = smtplib.SMTP(server)
smtp.sendmail(send_from, send_to, msg.as_string())
smtp.close()
It's much the same as the first example... But it should be easier to drop in.
Here is the modified version from Oli for python 3
import smtplib
from pathlib import Path
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, message, files=[],
server="localhost", port=587, username='', password='',
use_tls=True):
"""Compose and send email with provided info and attachments.
Args:
send_from (str): from name
send_to (list[str]): to name(s)
subject (str): message title
message (str): message body
files (list[str]): list of file paths to be attached to email
server (str): mail server host name
port (int): port number
username (str): server auth username
password (str): server auth password
use_tls (bool): use TLS mode
"""
msg = MIMEMultipart()
msg['From'] = send_from
msg['To'] = COMMASPACE.join(send_to)
msg['Date'] = formatdate(localtime=True)
msg['Subject'] = subject
msg.attach(MIMEText(message))
for path in files:
part = MIMEBase('application', "octet-stream")
with open(path, 'rb') as file:
part.set_payload(file.read())
encoders.encode_base64(part)
part.add_header('Content-Disposition',
'attachment; filename={}'.format(Path(path).name))
msg.attach(part)
smtp = smtplib.SMTP(server, port)
if use_tls:
smtp.starttls()
smtp.login(username, password)
smtp.sendmail(send_from, send_to, msg.as_string())
smtp.quit()
This is the code I ended up using:
import smtplib
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email import Encoders
SUBJECT = "Email Data"
msg = MIMEMultipart()
msg['Subject'] = SUBJECT
msg['From'] = self.EMAIL_FROM
msg['To'] = ', '.join(self.EMAIL_TO)
part = MIMEBase('application', "octet-stream")
part.set_payload(open("text.txt", "rb").read())
Encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment; filename="text.txt"')
msg.attach(part)
server = smtplib.SMTP(self.EMAIL_SERVER)
server.sendmail(self.EMAIL_FROM, self.EMAIL_TO, msg.as_string())
Code is much the same as Oli's post.
Code based from Binary file email attachment problem post.
from email.MIMEMultipart import MIMEMultipart
from email.MIMEText import MIMEText
from email.MIMEImage import MIMEImage
import smtplib
msg = MIMEMultipart()
msg.attach(MIMEText(file("text.txt").read()))
msg.attach(MIMEImage(file("image.png").read()))
# to send
mailer = smtplib.SMTP()
mailer.connect()
mailer.sendmail(from_, to, msg.as_string())
mailer.close()
Adapted from here.
Gmail version, working with Python 3.6 (note that you will need to change your Gmail settings to be able to send email via smtp from it:
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication
from os.path import basename
def send_mail(send_from: str, subject: str, text: str,
send_to: list, files= None):
send_to= default_address if not send_to else send_to
msg = MIMEMultipart()
msg['From'] = send_from
msg['To'] = ', '.join(send_to)
msg['Subject'] = subject
msg.attach(MIMEText(text))
for f in files or []:
with open(f, "rb") as fil:
ext = f.split('.')[-1:]
attachedfile = MIMEApplication(fil.read(), _subtype = ext)
attachedfile.add_header(
'content-disposition', 'attachment', filename=basename(f) )
msg.attach(attachedfile)
smtp = smtplib.SMTP(host="smtp.gmail.com", port= 587)
smtp.starttls()
smtp.login(username,password)
smtp.sendmail(send_from, send_to, msg.as_string())
smtp.close()
Usage:
username = 'my-address#gmail.com'
password = 'top-secret'
default_address = ['my-address2#gmail.com']
send_mail(send_from= username,
subject="test",
text="text",
send_to= None,
files= # pass a list with the full filepaths here...
)
To use with any other email provider, just change the smtp configurations.
Another way with python 3 (If someone is searching):
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
fromaddr = "sender mail address"
toaddr = "receiver mail address"
msg = MIMEMultipart()
msg['From'] = fromaddr
msg['To'] = toaddr
msg['Subject'] = "SUBJECT OF THE EMAIL"
body = "TEXT YOU WANT TO SEND"
msg.attach(MIMEText(body, 'plain'))
filename = "fileName"
attachment = open("path of file", "rb")
part = MIMEBase('application', 'octet-stream')
part.set_payload((attachment).read())
encoders.encode_base64(part)
part.add_header('Content-Disposition', "attachment; filename= %s" % filename)
msg.attach(part)
server = smtplib.SMTP('smtp.gmail.com', 587)
server.starttls()
server.login(fromaddr, "sender mail password")
text = msg.as_string()
server.sendmail(fromaddr, toaddr, text)
server.quit()
Make sure to allow “less secure apps” on your Gmail account
Because there are many answers here for Python 3, but none which show how to use the overhauled email library from Python 3.6, here is a quick copy+paste from the current email examples documentation.
(I have abridged it somewhat to remove frills like guessing the correct MIME type.)
Modern code which targets Python >3.5 should no longer use the email.message.Message API (including the various MIMEText, MIMEMultipart, MIMEBase etc classes) or the even older mimetypes mumbo jumbo.
from email.message import EmailMessage
import smtplib
msg = EmailMessage()
msg["Subject"] = "Our family reunion"
msg["From"] = "me <sender#example.org>"
msg["To"] = "recipient <victim#example.net>"
# definitely don't mess with the .preamble
msg.set_content("Hello, victim! Look at these pictures")
with open("path/to/attachment.png", "rb") as fp:
msg.add_attachment(
fp.read(), maintype="image", subtype="png")
# Notice how smtplib now includes a send_message() method
with smtplib.SMTP("localhost") as s:
s.send_message(msg)
The modern email.message.EmailMessage API is now quite a bit more versatile and logical than the older version of the library. There are still a few kinks around the presentation in the documentation (it's not obvious how to change the Content-Disposition: of an attachment, for example; and the discussion of the policy module is probably too obscure for most newcomers) and fundamentally, you still need to have some sort of idea of what the MIME structure should look like (though the library now finally takes care of a lot of the nitty-gritty around that). Perhaps see What are the "parts" in a multipart email? for a brief introduction.
Using localhost as your SMTP server obviously only works if you actually have an SMTP server running on your local computer. Properly getting email off your system is a fairly complex separate question. For simple requirements, probably use your existing email account and your provider's email server (search for examples of using port 587 with Google, Yahoo, or whatever you have - what exactly works depends somewhat on the provider; some will only support port 465, or legacy port 25 which is however now by and large impossible to use on public-facing servers because of spam filtering).
The simplest code I could get to is:
#for attachment email
from django.core.mail import EmailMessage
def attachment_email(request):
email = EmailMessage(
'Hello', #subject
'Body goes here', #body
'MyEmail#MyEmail.com', #from
['SendTo#SendTo.com'], #to
['bcc#example.com'], #bcc
reply_to=['other#example.com'],
headers={'Message-ID': 'foo'},
)
email.attach_file('/my/path/file')
email.send()
It was based on the official Django documentation
Other answers are excellent, though I still wanted to share a different approach in case someone is looking for alternatives.
Main difference here is that using this approach you can use HTML/CSS to format your message, so you can get creative and give some styling to your email. Though you aren't enforced to use HTML, you can also still use only plain text.
Notice that this function accepts sending the email to multiple recipients and also allows to attach multiple files.
I've only tried this on Python 2, but I think it should work fine on 3 as well:
import os.path
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
def send_email(subject, message, from_email, to_email=[], attachment=[]):
"""
:param subject: email subject
:param message: Body content of the email (string), can be HTML/CSS or plain text
:param from_email: Email address from where the email is sent
:param to_email: List of email recipients, example: ["a#a.com", "b#b.com"]
:param attachment: List of attachments, exmaple: ["file1.txt", "file2.txt"]
"""
msg = MIMEMultipart()
msg['Subject'] = subject
msg['From'] = from_email
msg['To'] = ", ".join(to_email)
msg.attach(MIMEText(message, 'html'))
for f in attachment:
with open(f, 'rb') as a_file:
basename = os.path.basename(f)
part = MIMEApplication(a_file.read(), Name=basename)
part['Content-Disposition'] = 'attachment; filename="%s"' % basename
msg.attach(part)
email = smtplib.SMTP('your-smtp-host-name.com')
email.sendmail(from_email, to_email, msg.as_string())
I hope this helps! :-)
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
import smtplib
import mimetypes
import email.mime.application
smtp_ssl_host = 'smtp.gmail.com' # smtp.mail.yahoo.com
smtp_ssl_port = 465
s = smtplib.SMTP_SSL(smtp_ssl_host, smtp_ssl_port)
s.login(email_user, email_pass)
msg = MIMEMultipart()
msg['Subject'] = 'I have a picture'
msg['From'] = email_user
msg['To'] = email_user
txt = MIMEText('I just bought a new camera.')
msg.attach(txt)
filename = 'introduction-to-algorithms-3rd-edition-sep-2010.pdf' #path to file
fo=open(filename,'rb')
attach = email.mime.application.MIMEApplication(fo.read(),_subtype="pdf")
fo.close()
attach.add_header('Content-Disposition','attachment',filename=filename)
msg.attach(attach)
s.send_message(msg)
s.quit()
For explanation, you can use this link it explains properly
https://medium.com/#sdoshi579/to-send-an-email-along-with-attachment-using-smtp-7852e77623
from email.mime.multipart import MIMEMultipart
from email.mime.image import MIMEImage
from email.mime.text import MIMEText
import smtplib
msg = MIMEMultipart()
password = "password"
msg['From'] = "from_address"
msg['To'] = "to_address"
msg['Subject'] = "Attached Photo"
msg.attach(MIMEImage(file("abc.jpg").read()))
file = "file path"
fp = open(file, 'rb')
img = MIMEImage(fp.read())
fp.close()
msg.attach(img)
server = smtplib.SMTP('smtp.gmail.com: 587')
server.starttls()
server.login(msg['From'], password)
server.sendmail(msg['From'], msg['To'], msg.as_string())
server.quit()
I know this is an old question but I thought there must be an easier way of doing this than the other examples, thus I made a library that solves this cleanly without polluting your codebase. Including attachments is super easy:
from redmail import EmailSender
from pathlib import Path
# Configure an email sender
email = EmailSender(
host="<SMTP HOST>", port=0,
user_name="me#example.com", password="<PASSWORD>"
)
# Send an email
email.send(
sender="me#example.com",
receivers=["you#example.com"],
subject="An example email"
attachments={
"myfile.txt": Path("path/to/a_file.txt"),
"myfile.html": "<h1>Content of a HTML attachment</h1>"
}
)
You may also directly attach bytes, a Pandas DataFrame (which is converted to format depending on file extension in the key), a Matplotlib Figure or a Pillow Image. The library is most likely all the features you need for an email sender (has a lot more than attachments).
To install:
pip install redmail
Use it any way you like. I also wrote extensive documentation: https://red-mail.readthedocs.io/en/latest/
None of the currently given answers here will work correctly with non-ASCII symbols in filenames with clients like GMail, Outlook 2016, and others that don't support RFC 2231 (e.g., see here). The Python 3 code below is adapted from some other stackoverflow answers (sorry, didn't save the origin links) and odoo/openerp code for Python 2.7 (see ir_mail_server.py). It works correctly with GMail and others, and also uses SSL.
import smtplib, ssl
from os.path import basename
from email.mime.base import MIMEBase
from mimetypes import guess_type
from email.encoders import encode_base64
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.utils import COMMASPACE, formatdate
from email.charset import Charset
def try_coerce_ascii(string_utf8):
"""Attempts to decode the given utf8-encoded string
as ASCII after coercing it to UTF-8, then return
the confirmed 7-bit ASCII string.
If the process fails (because the string
contains non-ASCII characters) returns ``None``.
"""
try:
string_utf8.encode('ascii')
except UnicodeEncodeError:
return
return string_utf8
def encode_header_param(param_text):
"""Returns an appropriate RFC 2047 encoded representation of the given
header parameter value, suitable for direct assignation as the
param value (e.g. via Message.set_param() or Message.add_header())
RFC 2822 assumes that headers contain only 7-bit characters,
so we ensure it is the case, using RFC 2047 encoding when needed.
:param param_text: unicode or utf-8 encoded string with header value
:rtype: string
:return: if ``param_text`` represents a plain ASCII string,
return the same 7-bit string, otherwise returns an
ASCII string containing the RFC2047 encoded text.
"""
if not param_text: return ""
param_text_ascii = try_coerce_ascii(param_text)
return param_text_ascii if param_text_ascii\
else Charset('utf8').header_encode(param_text)
smtp_server = '<someserver.com>'
smtp_port = 465 # Default port for SSL
sender_email = '<sender_email#some.com>'
sender_password = '<PASSWORD>'
receiver_emails = ['<receiver_email_1#some.com>', '<receiver_email_2#some.com>']
subject = 'Test message'
message = """\
Hello! This is a test message with attachments.
This message is sent from Python."""
files = ['<path1>/файл1.pdf', '<path2>/файл2.png']
# Create a secure SSL context
context = ssl.create_default_context()
msg = MIMEMultipart()
msg['From'] = sender_email
msg['To'] = COMMASPACE.join(receiver_emails)
msg['Date'] = formatdate(localtime=True)
msg['Subject'] = subject
msg.attach(MIMEText(message))
for f in files:
mimetype, _ = guess_type(f)
mimetype = mimetype.split('/', 1)
with open(f, "rb") as fil:
part = MIMEBase(mimetype[0], mimetype[1])
part.set_payload(fil.read())
encode_base64(part)
filename_rfc2047 = encode_header_param(basename(f))
# The default RFC 2231 encoding of Message.add_header() works in Thunderbird but not GMail
# so we fix it by using RFC 2047 encoding for the filename instead.
part.set_param('name', filename_rfc2047)
part.add_header('Content-Disposition', 'attachment', filename=filename_rfc2047)
msg.attach(part)
with smtplib.SMTP_SSL(smtp_server, smtp_port, context=context) as server:
server.login(sender_email, sender_password)
server.sendmail(sender_email, receiver_emails, msg.as_string())
Here is an updated version for Python 3.6 and newer using the EmailMessage class of the overhauled email module in the Python standard library.
import mimetypes
import os
import smtplib
from email.message import EmailMessage
username = "user#example.com"
password = "password"
smtp_url = "smtp.example.com"
port = 587
def send_mail(subject: str, send_from: str, send_to: str, message: str, directory: str, filename: str):
# Create the email message
msg = EmailMessage()
msg['Subject'] = subject
msg['From'] = send_from
msg['To'] = send_to
# Set email content
msg.set_content(message)
path = directory + filename
if os.path.exists(path):
ctype, encoding = mimetypes.guess_type(path)
if ctype is None or encoding is not None:
# No guess could be made, or the file is encoded (compressed), so
# use a generic bag-of-bits type.
ctype = 'application/octet-stream'
maintype, subtype = ctype.split('/', 1)
# Add email attachment
with open(path, 'rb') as fp:
msg.add_attachment(fp.read(),
maintype=maintype,
subtype=subtype,
filename=filename)
smtp = smtplib.SMTP(smtp_url, port)
smtp.starttls() # for using port 587
smtp.login(username, password)
smtp.send_message(msg)
smtp.quit()
You can find more examples here.
Below is combination of what I've found from SoccerPlayer's post Here and the following link that made it easier for me to attach an xlsx file. Found Here
file = 'File.xlsx'
username=''
password=''
send_from = ''
send_to = 'recipient1 , recipient2'
Cc = 'recipient'
msg = MIMEMultipart()
msg['From'] = send_from
msg['To'] = send_to
msg['Cc'] = Cc
msg['Date'] = formatdate(localtime = True)
msg['Subject'] = ''
server = smtplib.SMTP('smtp.gmail.com')
port = '587'
fp = open(file, 'rb')
part = MIMEBase('application','vnd.ms-excel')
part.set_payload(fp.read())
fp.close()
encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment', filename='Name File Here')
msg.attach(part)
smtp = smtplib.SMTP('smtp.gmail.com')
smtp.ehlo()
smtp.starttls()
smtp.login(username,password)
smtp.sendmail(send_from, send_to.split(',') + msg['Cc'].split(','), msg.as_string())
smtp.quit()
You can also specify the type of attachment you want in your e-mail, as an example I used pdf:
def send_email_pdf_figs(path_to_pdf, subject, message, destination, password_path=None):
## credits: http://linuxcursor.com/python-programming/06-how-to-send-pdf-ppt-attachment-with-html-body-in-python-script
from socket import gethostname
#import email
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import smtplib
import json
server = smtplib.SMTP('smtp.gmail.com', 587)
server.starttls()
with open(password_path) as f:
config = json.load(f)
server.login('me#gmail.com', config['password'])
# Craft message (obj)
msg = MIMEMultipart()
message = f'{message}\nSend from Hostname: {gethostname()}'
msg['Subject'] = subject
msg['From'] = 'me#gmail.com'
msg['To'] = destination
# Insert the text to the msg going by e-mail
msg.attach(MIMEText(message, "plain"))
# Attach the pdf to the msg going by e-mail
with open(path_to_pdf, "rb") as f:
#attach = email.mime.application.MIMEApplication(f.read(),_subtype="pdf")
attach = MIMEApplication(f.read(),_subtype="pdf")
attach.add_header('Content-Disposition','attachment',filename=str(path_to_pdf))
msg.attach(attach)
# send msg
server.send_message(msg)
inspirations/credits to: http://linuxcursor.com/python-programming/06-how-to-send-pdf-ppt-attachment-with-html-body-in-python-script
Try This i hope this might help
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
fromaddr = "youremailhere"
toaddr = input("Enter The Email Adress You want to send to: ")
# instance of MIMEMultipart
msg = MIMEMultipart()
# storing the senders email address
msg['From'] = fromaddr
# storing the receivers email address
msg['To'] = toaddr
# storing the subject
msg['Subject'] = input("What is the Subject:\t")
# string to store the body of the mail
body = input("What is the body:\t")
# attach the body with the msg instance
msg.attach(MIMEText(body, 'plain'))
# open the file to be sent
filename = input("filename:")
attachment = open(filename, "rb")
# instance of MIMEBase and named as p
p = MIMEBase('application', 'octet-stream')
# To change the payload into encoded form
p.set_payload((attachment).read())
# encode into base64
encoders.encode_base64(p)
p.add_header('Content-Disposition', "attachment; filename= %s" % filename)
# attach the instance 'p' to instance 'msg'
msg.attach(p)
# creates SMTP session
s = smtplib.SMTP('smtp.gmail.com', 587)
# start TLS for security
s.starttls()
# Authentication
s.login(fromaddr, "yourpaswordhere)
# Converts the Multipart msg into a string
text = msg.as_string()
# sending the mail
s.sendmail(fromaddr, toaddr, text)
# terminating the session
s.quit()
Had a bit of a hussle in getting my script to send generic attachments but after a bit of work doing research and skimming through articles on this post, I finally came up with the following
# to query:
import sys
import ast
from datetime import datetime
import smtplib
import mimetypes
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from email import encoders
from email.message import Message
from email.mime.audio import MIMEAudio
from email.mime.base import MIMEBase
from email.mime.image import MIMEImage
from email.mime.text import MIMEText
from dotenv import load_dotenv, dotenv_values
load_dotenv() # load environment variables from .env
'''
sample .env file
# .env file
SECRET_KEY="gnhfpsjxxxxxxxx"
DOMAIN="GMAIL"
TOP_LEVEL_DOMAIN="COM"
EMAIL="CHESERExxxxxx#${DOMAIN}.${TOP_LEVEL_DOMAIN}"
TO_ADDRESS = ("cheseremxxxxx#gmail.com","cheserek#gmail.com")#didn't use this in the code but you can load recipients from here
'''
import smtplib
tls_port = 587
ssl_port = 465
smtp_server_domain_names = {'GMAIL': ('smtp.gmail.com', tls_port, ssl_port),
'OUTLOOK': ('smtp-mail.outlook.com', tls_port, ssl_port),
'YAHOO': ('smtp.mail.yahoo.com', tls_port, ssl_port),
'AT&T': ('smtp.mail.att.net', tls_port, ssl_port),
}
# todo: Ability to choose mail server provider
# auto read in from the dictionary the respective mail server address and the tls and ssl ports
class Bimail:
def __init__(self, subject, recipients):
self.subject = subject
self.recipients = recipients
self.htmlbody = ''
self.mail_username = 'will be loaded from .env file'
self.mail_password = 'loaded from .env file as well'
self.attachments = []
# Creating an smtp object
# todo: if gmail passed in use gmail's dictionary values
def setup_mail_client(self, domain_key_to_use="GMAIL",
email_servers_domains_dict=smtp_server_domain_names):
"""
:param report_pdf:
:type to_address: str
"""
smtpObj = None
encryption_status = True
config = dotenv_values(".env")
# check if the domain_key exists from within the available email-servers-domains dict file passed in
# else throw an error
# read environment file to get the Domain to be used
if f"{domain_key_to_use}" in email_servers_domains_dict.keys():
# if the key is found do the following
# 1.extract the domain,tls,ssl ports from email_servers dict for use in program
try:
values_tuple = email_servers_domains_dict.get(f"{domain_key_to_use}")
ssl_port = values_tuple[2]
tls_port = values_tuple[1]
smtp_server = values_tuple[0]
smtpObj = smtplib.SMTP(smtp_server, tls_port)
print(f"Success connect with tls on {tls_port}")
print('Awaiting for connection encryption via startttls()')
encryption_status = False
except:
print(f"Failed connection via tls on port {tls_port}")
try:
smtpObj = smtplib.SMTP_SSL(smtp_server, ssl_port)
print(f"Success connect with ssl on {ssl_port}")
encryption_status = True
except:
print(f"Failed connection via ssl on port {ssl_port}")
finally:
print("Within Finally block")
if not smtpObj:
print("Failed!!! no Internet connection")
else:
# if connection channel is unencrypted via the use of tls encrypt it
if not encryption_status:
status = smtpObj.starttls()
if status[0] == 220:
print("Successfully Encrypted tls channel")
print("Successfully Connected!!!! Requesting Login")
# Loading .env file values to config variable
#load Login Creds from ENV File
self.mail_username = f'{config.get("EMAIL")}'
self.mail_password = f'{cofig.get("SECRET_KEY")}'
status = smtpObj.login(self.mail_usernam,self.mail_password)
if status[0] == 235:
print("Successfully Authenticated User to xxx account")
success = self.send(smtpObj, f'{config.get("EMAIL")}')
if not bool(success):
print(f"Success in Sending Mail to {success}")
print("Disconnecting from Server INstance")
quit_result = smtpObj.quit()
else:
print(f"Failed to Post {success}!!!")
print(f"Quiting anyway !!!")
quit_result = smtpObj.quit()
else:
print("Application Specific Password is Required")
else:
print("World")
def send(self,smtpObj,from_address):
msg = MIMEMultipart('alternative')
msg['From'] = from_address
msg['Subject'] = self.subject
msg['To'] = ", ".join(self.recipients) # to must be array of the form ['mailsender135#gmail.com']
msg.preamble = "preamble goes here"
# check if there are attachments if yes, add them
if self.attachments:
self.attach(msg)
# add html body after attachments
msg.attach(MIMEText(self.htmlbody, 'html'))
# send
print(f"Attempting Email send to the following addresses {self.recipients}")
result = smtpObj.sendmail(from_address, self.recipients,msg.as_string())
return result
def htmladd(self, html):
self.htmlbody = self.htmlbody + '<p></p>' + html
def attach(self, msg):
for f in self.attachments:
ctype, encoding = mimetypes.guess_type(f)
if ctype is None or encoding is not None:
ctype = "application/octet-stream"
maintype, subtype = ctype.split("/", 1)
if maintype == "text":
fp = open(f)
# Note: we should handle calculating the charset
attachment = MIMEText(fp.read(), _subtype=subtype)
fp.close()
elif maintype == "image":
fp = open(f, "rb")
attachment = MIMEImage(fp.read(), _subtype=subtype)
fp.close()
elif maintype == "ppt":
fp = open(f, "rb")
attachment = MIMEApplication(fp.read(), _subtype=subtype)
fp.close()
elif maintype == "audio":
fp = open(f, "rb")
attachment = MIMEAudio(fp.read(), _subtype=subtype)
fp.close()
else:
fp = open(f, "rb")
attachment = MIMEBase(maintype, subtype)
attachment.set_payload(fp.read())
fp.close()
encoders.encode_base64(attachment)
attachment.add_header("Content-Disposition", "attachment", filename=f)
attachment.add_header('Content-ID', '<{}>'.format(f))
msg.attach(attachment)
def addattach(self, files):
self.attachments = self.attachments + files
# example below
if __name__ == '__main__':
# subject and recipients
mymail = Bimail('Sales email ' + datetime.now().strftime('%Y/%m/%d'),
['cheseremxx#gmail.com', 'tkemboxxx#gmail.com'])
# start html body. Here we add a greeting.
mymail.htmladd('Good morning, find the daily summary below.')
# Further things added to body are separated by a paragraph, so you do not need to worry about newlines for new sentences
# here we add a line of text and an html table previously stored in the variable
mymail.htmladd('Daily sales')
mymail.addattach(['htmlsalestable.xlsx'])
# another table name + table
mymail.htmladd('Daily bestsellers')
mymail.addattach(['htmlbestsellertable.xlsx'])
# add image chart title
mymail.htmladd('Weekly sales chart')
# attach image chart
mymail.addattach(['saleschartweekly.png'])
# refer to image chart in html
mymail.htmladd('<img src="cid:saleschartweekly.png"/>')
# attach another file
mymail.addattach(['MailSend.py'])
# send!
mymail.setup_mail_client( domain_key_to_use="GMAIL",email_servers_domains_dict=smtp_server_domain_names)
With my code you can send email attachments using gmail you will need to:
Set your gmail address at ___YOUR SMTP EMAIL HERE___
Set your gmail account password at __YOUR SMTP PASSWORD HERE___
In the ___EMAIL TO RECEIVE THE MESSAGE__ part you need to set the destination email address.
Alarm notification is the subject.
Someone has entered the room, picture attached is the body.
["/home/pi/webcam.jpg"] is an image attachment.
Here is the full code:
#!/usr/bin/env python
import smtplib
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email.Utils import COMMASPACE, formatdate
from email import Encoders
import os
USERNAME = "___YOUR SMTP EMAIL HERE___"
PASSWORD = "__YOUR SMTP PASSWORD HERE___"
def sendMail(to, subject, text, files=[]):
assert type(to)==list
assert type(files)==list
msg = MIMEMultipart()
msg['From'] = USERNAME
msg['To'] = COMMASPACE.join(to)
msg['Date'] = formatdate(localtime=True)
msg['Subject'] = subject
msg.attach( MIMEText(text) )
for file in files:
part = MIMEBase('application', "octet-stream")
part.set_payload( open(file,"rb").read() )
Encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment; filename="%s"'
% os.path.basename(file))
msg.attach(part)
server = smtplib.SMTP('smtp.gmail.com:587')
server.ehlo_or_helo_if_needed()
server.starttls()
server.ehlo_or_helo_if_needed()
server.login(USERNAME,PASSWORD)
server.sendmail(USERNAME, to, msg.as_string())
server.quit()
sendMail( ["___EMAIL TO RECEIVE THE MESSAGE__"],
"Alarm notification",
"Someone has entered the room, picture attached",
["/home/pi/webcam.jpg"] )