I'm using python 2.7 and boto3.
I can not figure out a way to add attachments to SES in python.
The closest thing I found was this page.
So far what I have is this:
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
import boto3
# via http://codeadict.wordpress.com/2010/02/11/send-e-mails-with-attachment-in-python/
ses = boto3.client('ses')
msg = MIMEMultipart()
msg['Subject'] = 'weekly report'
msg['From'] = email
msg['To'] = other_email
# what a recipient sees if they don't use an email reader
msg.preamble = 'Multipart message.\n'
# the message body
part = MIMEText('Howdy -- here is the data from last week.')
msg.attach(part)
# the attachment
part = MIMEApplication(open('cat.jpg', 'rb').read())
part.add_header('Content-Disposition', 'attachment', filename='cat.jpg')
msg.attach(part)
result = ses.send_raw_email(
Source=msg['From'],
Destinations=msg['To'],
RawMessage=msg
)
# and send the message
print result
And i get:
ParamValidationError: Parameter validation failed:
Invalid type for parameter RawMessage, value: From nobody Tue Jul 25 11:21:41 2017
Content-Type: multipart/mixed; boundary="===============0285276385=="
MIME-Version: 1.0
Subject: weekly report
From: email
To: other_email
"email" and "other_email" are censored but in String format 'e#mail.xxx'.
The address is authorized through AWS and the Key and Secret key are already implemented through boto3.
Also got this at the bottom of the output:
type: <type 'instance'>, valid types: <type 'dict'>
Invalid type for parameter Destinations,
value: other_email,
type: <type 'str'>, valid types: <type 'list'>, <type 'tuple'>
I figured it out! There are probably better ways of doing this, but it worked for me. Please let me know how to improve on this. Thank you.
New code:
to_emails = [target_email1, target_email2]
ses = boto3.client('ses')
msg = MIMEMultipart()
msg['Subject'] = 'weekly report'
msg['From'] = from_email
msg['To'] = to_emails[0]
# what a recipient sees if they don't use an email reader
msg.preamble = 'Multipart message.\n'
# the message body
part = MIMEText('Howdy -- here is the data from last week.')
msg.attach(part)
# the attachment
part = MIMEApplication(open('cat.jpg', 'rb').read())
part.add_header('Content-Disposition', 'attachment', filename='cat.jpg')
msg.attach(part)
result = ses.send_raw_email(
Source=msg['From'],
Destinations=to_emails,
RawMessage={'Data': msg.as_string()}
)
# and send the message
print result
Related
I have to sendmail at the end of my code with csv attached containing a dataframe.
Im doing it at AWS Lambda using boto3 to call SES as it follows.
def sendMail1(value, df):
subject = "Comission"
client = boto3.client("ses")
body = f"""
Comission value is {value}.
"""
message = {"Subject": {"Data": subject}, "Body": {"Html": {"Data": body}}}
attachment = df.to_csv(f"Comission.csv", index=False)
response = client.send_email(Source = "myemail#gmail.com", Destination = {"ToAddresses": ["youremail#gmail.com"]}, Message = message, Attachment = attachment)
I had no ideia how to do it, I tried df.to_csv method and include it as attachment. Did not work.
The rest of the code works without the attachment parts, but I need to attach my df to the e-mail.
Do you guys have any idea how to do it?
df.to_csv(f"Comission.csv", index=False)
to_emails = [target_email1, target_email2]
ses = boto3.client('ses')
msg = MIMEMultipart()
msg['Subject'] = 'weekly report'
msg['From'] = from_email
msg['To'] = to_emails[0]
# what a recipient sees if they don't use an email reader
msg.preamble = 'Multipart message.\n'
# the message body
part = MIMEText('Howdy -- here is the data from last week.')
msg.attach(part)
# the attachment
part = MIMEApplication(open('Comission.csv', 'rb').read())
part.add_header('Content-Disposition', 'attachment', filename='Comission.csv')
msg.attach(part)
result = ses.send_raw_email(
Source=msg['From'],
Destinations=to_emails,
RawMessage={'Data': msg.as_string()})
# and send the message
print result
I'm just looking to send an email with 3 csv file attachments. When i get it to run, trying a solution i found on here, it gives me a BIN file instead of the 3 files. Or, trying another solution, it will only send the last of the the 3 files. When i run the code below, its gives me TypeError: add.header() takes 3 positional arguments but 4 were given.
I understand that it can be done with a function, but i'm not sure how to have it pull all three files into it. I've spent numerous hours trying to figure it out.
Posting it on here is my last resort. I appreciate any help in finding a solution.
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
import time
import os
msg = MIMEMultipart()
msg['From'] = EMAIL_FROM
msg['To'] = ", ".join(RECIPIENT_LIST)
msg['Subject'] = 'Louisiana Contractors List'
#email content
message = """<html>
<body>
Attached is the Louisiana Contractors Spreadsheet.
<br><br>
Let me know if you have any questions
</body>
</html>
"""
msg.attach(MIMEText(message, 'html'))
files = [
'C:/Users/rkrouse/Downloads/search-results.csv',
'C:/Users/rkrouse/Downloads/search-results(1).csv',
'C:/Users/rkrouse/Downloads/search-results(2).csv']
for a_file in files:
attachment = open(a_file, 'rb')
part = MIMEBase('application','octet-stream')
part.set_payload((attachment).read())
part.add_header('Content-Disposition', 'attachment', a_file = os.path.basename('C:/Users/rkrouse/Downloads/search-results.csv'))
encoders.encode_base64(part)
msg.attach(part)
for a_file in files:
attachment = open(a_file, 'rb')
part = MIMEBase('application','octet-stream')
part.set_payload((attachment).read())
part.add_header('Content-Disposition', 'attachment', a_file = os.path.basename('C:/Users/rkrouse/Downloads/search-results(1).csv'))
encoders.encode_base64(part)
msg.attach(part)
for a_file in files:
attachment = open(a_file, 'rb')
part = MIMEBase('application','octet-stream')
part.set_payload(attachment.read())
part.add_header('Content-Disposition', 'attachment', a_file = os.path.basename('C:/Users/rkrouse/Downloads/search-results(2).csv'))
encoders.encode_base64(part)
msg.attach(part)
#sends email
smtpserver = smtplib.SMTP(EMAIL_SERVER, EMAIL_PORT)
smtpserver.sendmail(EMAIL_FROM, RECIPIENT_LIST, msg.as_string())
smtpserver.quit()
Updated tested solution:
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
import time
import os
msg = MIMEMultipart()
msg['From'] = EMAIL_FROM
msg['To'] = ", ".join(RECIPIENT_LIST)
msg['Subject'] = 'Louisiana Contractors List'
#email content
message = """<html>
<body>
Attached is the Louisiana Contractors Spreadsheet.
<br><br>
Let me know if you have any questions
</body>
</html>
"""
msg.attach(MIMEText(message, 'html'))
files = [
'C:/Users/rkrouse/Downloads/search-results.csv',
'C:/Users/rkrouse/Downloads/search-results(1).csv',
'C:/Users/rkrouse/Downloads/search-results(2).csv']
for a_file in files:
attachment = open(a_file, 'rb')
file_name = os.path.basename(a_file)
part = MIMEBase('application','octet-stream')
part.set_payload(attachment.read())
part.add_header('Content-Disposition',
'attachment',
filename=file_name)
encoders.encode_base64(part)
msg.attach(part)
#sends email
smtpserver = smtplib.SMTP(EMAIL_SERVER, EMAIL_PORT)
smtpserver.sendmail(EMAIL_FROM, RECIPIENT_LIST, msg.as_string())
smtpserver.quit()
As you can see you need to specify the filename in the base64 encoding.
Also you are iterating the files three time.
A for loop is used to go through a list, set, array, etc. One for loop (as all attachments are in one list) should be enough.
Following is the simple snippet that I used to send an email to multiple people with multiple file attachments.
# -*- coding: utf-8 -*-
import smtplib
import mimetypes
from email.mime.multipart import MIMEMultipart
from email import encoders
from email.mime.audio import MIMEAudio
from email.mime.base import MIMEBase
from email.mime.image import MIMEImage
from email.mime.text import MIMEText
import ntpath
sender_address = 'vijay.anand#xxxx.com'
default_subject = 'Test email from {}'.format(sender_address)
smtp_server_address = '10.111.41.25'
smtp_port_number = 25
default_message = message = """<html>
<body>
Attached is the Louisiana Contractors Spreadsheet.
<br><br>
Let me know if you have any questions
</body>
</html>
"""
def send_by_smtp(to=None, cc=None, bcc=None, subject=None, attachments=None, attachment_type='plain'):
"""
Snippet to send an email to multiple people along with multiple attachments.
:param to: list of emails
:param cc: list of emails
:param bcc: list of emails
:param subject: Email Subject
:param attachments: list of file paths
:param attachment_type: 'plain' or 'html'
:return: None
"""
email_from = sender_address
email_to = list()
files_to_send = attachments
msg = MIMEMultipart()
msg["From"] = email_from
if to:
to = list(set(to))
email_to += to
msg["To"] = ', '.join(to)
if cc:
cc = list(set(cc))
email_to += cc
msg["Cc"] = ', '.join(cc)
if bcc:
bcc = list(set(bcc))
email_to += bcc
msg["Bcc"] = ', '.join(bcc)
if subject:
msg["Subject"] = subject
msg.preamble = subject
else:
msg["Subject"] = default_subject
msg.preamble = default_subject
body = default_message
msg.attach(MIMEText(body, attachment_type))
if files_to_send:
for file_to_send in files_to_send:
content_type, encoding = mimetypes.guess_type(file_to_send)
if content_type is None or encoding is not None:
content_type = "application/octet-stream"
maintype, subtype = content_type.split("/", 1)
if maintype == "text":
with open(file_to_send) as fp:
# Note: we should handle calculating the charset
attachment = MIMEText(fp.read(), _subtype=subtype)
elif maintype == "image":
with open(file_to_send, "rb") as fp:
attachment = MIMEImage(fp.read(), _subtype=subtype)
elif maintype == "audio":
with open(file_to_send, "rb")as fp:
attachment = MIMEAudio(fp.read(), _subtype=subtype)
else:
with open(file_to_send, "rb") as fp:
attachment = MIMEBase(maintype, subtype)
attachment.set_payload(fp.read())
encoders.encode_base64(attachment)
attachment.add_header("Content-Disposition", "attachment", filename=ntpath.basename(file_to_send))
msg.attach(attachment)
try:
smtp_obj = smtplib.SMTP(host=smtp_server_address, port=smtp_port_number, timeout=300)
smtp_obj.sendmail(from_addr=email_from, to_addrs=list(set([email_from] + email_to)), msg=msg.as_string())
print("Successfully sent email to {}".format(str(email_to)))
smtp_obj.quit()
return True
except smtplib.SMTPException:
print("Error: unable to send email")
return False
if __name__ == '__main__':
print('Send an email using Python')
result = send_by_smtp(to=['vijay#xxxx.com', 'tha#xxx.com'],
cc=['anandp#xxxx.com', 'nitha#xxxx.com'],
bcc=['vij#xxxx.com', 'Sun#xxxx.com'],
subject='Louisiana Contractors List',
attachments=['test.txt', '1.JPG', '2.PNG', '3.PNG', '4.PNG'],
attachment_type='html')
if result:
print('Email Sent Successfully')
else:
print('Email Sending Failed')
I need to send a email with Excel attachment。
my code is like below , it is ok to send the email ,
but when I received the email, the attachment file is not Excel files~~
it seems that the wrong format I have attached~~~
I have add different email address to receive this email,
but they were all received the unknown format files
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import os
import datetime
import sys
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.header import Header
from email.mime.base import MIMEBase
from email import encoders
mail_host = "mysever" # 设置服务器
mail_user = "me" # 用户名
mail_pass = "me123" # 口令
EMAILHOME = u'F:\Workfiles\weekreport\\forupdate'
sender = 'me#gmail.com'
receivers = ['aaaaaa#qq.com'] # 接收邮件,可设置为你的QQ邮箱或者其他邮箱
def getReceiverlist(filename):
lif = open(filename)
li = lif.readlines()
lif.close()
for x in range(len(li)):
li[x] = li[x].strip(os.linesep)
while '' in li:
li.remove('')
return li
def aisendmail():
ret = True
try:
message = MIMEMultipart()
message['From'] = Header("myname", 'utf-8')
message['To'] = Header("youname", 'utf-8')
message.attach(MIMEText('weekreport', 'plain', 'utf-8')) # 三个参数:第一个为文本内容,第二个 plain 设置文本格式,第三个 utf-8 设置编码
subject = 'myname-weekreport'
message['Subject'] = Header(subject, 'utf-8')
att1 = MIMEBase('application', "octet-stream")
att1.set_payload(open(u"F:\Workfiles\weekreport\\forupdate\myname_weekreport_20170821.xlsx",'rb').read())
encoders.encode_base64(att1)
att1.add_header('Content-Disposition', 'attachment; filename="myname-weekreport"')
message.attach(att1)
if os.path.exists(EMAILHOME + r'\receivers.txt'):
receiverslist = getReceiverlist(EMAILHOME + r'\receivers.txt')
print("receicerlist include:", receiverslist)
if len(receiverslist) == 0:
print"no receiver!!!"
receiverslist = receivers
else:
receiverslist = receivers
server = smtplib.SMTP()
server.connect(mail_host, 25) # 发件人邮箱中的SMTP服务器,端口是25
server.login(mail_user, mail_pass) # 括号中对应的是发件人邮箱账号、邮箱密码
server.sendmail(sender, receiverslist, message.as_string()) # 括号中对应的是发件人邮箱账号、收件人邮箱账号、发送邮件
server.quit() # 关闭连接
except smtplib.SMTPException: # 如果 try 中的语句没有执行,则会执行下面的 ret=False
ret = False
return ret
result = aisendmail()
if result:
print "邮件发送成功"
else:
print "Error: 无法发送邮件"
I follow different ways to add excel attachment as below: but they were all failed(it means it could not receive excel format file)
Method 1:
att1 = MIMEBase('application', 'octet-stream') #'octet-stream': binary data
att1.set_payload(open(file, 'rb').read())
encoders.encode_base64(att1)
att1.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(file))
msg.attach(att1)
Result:
received a unknown format file
Method 2:
with open(u"F:\Workfiles\周报\\forupdate\xxx_周报_20170821.xlsx", "rb") as fil:
part = MIMEApplication(
fil.read(),
Name=basename(u"F:\Workfiles\周报\\forupdate\xxx_周报_20170821.xlsx")
)
part['Content-Disposition'] = 'attachment; filename="%s"' % basename(u"F:\Workfiles\周报\\forupdate\xxx_周报_20170821.xlsx")
message.attach(part)
Result:
received a bin format file
Method 3:
att1 = MIMEApplication(open('foo.xlsx','rb').read())
att1.add_header('Content-Disposition', 'attachment', filename="foo.xlsx")
msg.attach(att1)
Result:
receive a unknown format file
Try this code to add the attachment:
with open(f, "rb") as fil:
part = MIMEApplication(
fil.read(),
Name=basename(f)
)
part['Content-Disposition'] = 'attachment; filename="%s"' % basename(f)
msg.attach(part)
I was trying to send a body formatted in HTML, and add an excel file as an attachment - this took me ages to figure out, so best thought I should share my solution!
from email.message import EmailMessage
msg = EmailMessage()
msg['Subject'] = 'This is my subject line'
msg['To'] = xxxxx#xmail.com
msg['From'] = yyyyy#ymail.com
msg.add_alternative(f"""\
<!DOCTYPE html>
<html>
<body>
<h3>This is my message!</h3>
</body>
</html>""",
subtype='html')
with open('MyExcelFile.xlsx', 'rb') as fh:
attachment = fh.read()
msg.add_related(attachment, maintype='application', subtype='xlsx', filename='MyExcelFile.xlsx')
with smtplib.SMTP_SSL(host='smtp.gmail.com', port=465) as smtp:
smtp.login('obviouslyfake#gmail.com', 'WhoDoYouThinkIAm')
smtp.send_message(msg)
I'm trying to email multiple recipients using the pyton script below. I've searched the forum for answers, but have not been able to implement any of them correctly. If anyone has a moment to review my script and spot/resolve the problem it would be greatly appreciated.
Here's my script, I gather my issue is in the 'sendmail' portion, but can't figure out how to fix it:
gmail_user = "sender#email.com"
gmail_pwd = "sender_password"
recipients = ['recipient1#email.com','recipient2#email.com']
def mail(to, subject, text, attach):
msg = MIMEMultipart()
msg['From'] = gmail_user
msg['To'] = ", ".join(recipients)
msg['Subject'] = subject
msg.attach(MIMEText(text))
part = MIMEBase('application', 'octet-stream')
part.set_payload(open(attach, 'rb').read())
Encoders.encode_base64(part)
part.add_header('Content-Disposition',
'attachment; filename="%s"' % os.path.basename(attach))
msg.attach(part)
mailServer = smtplib.SMTP("smtp.gmail.com", 587)
mailServer.ehlo()
mailServer.starttls()
mailServer.ehlo()
mailServer.login(gmail_user, gmail_pwd)
mailServer.sendmail(gmail_user, to, msg.as_string())
mailServer.close()
mail("recipient1#email.com, recipient2#email.com",
"Subject",
"Message",
"attchachment")
Any insight would be greatly appreciated.
Best,
Matt
It should be more like
mail(["recipient1#email.com", "recipient2#email.com"],
"Subject",
"Message",
"attchachment")
You already have a array of recipients declared,that too globally,You can use that without passing it as an argument to mail.
I wrote this bit of code to do exactly what you want. If you find a bug let me know (I've tested it and it works):
import email as em
import smtplib as smtp
import os
ENDPOINTS = {KEY: 'value#domain.com'}
class BoxWriter(object):
def __init__(self):
pass
def dispatch(self, files, box_target, additional_targets=None, email_subject=None, body='New figures'):
"""
Send an email to multiple recipients
:param files: list of files to send--requires full path
:param box_target: Relevant entry ENDPOINTS dict
:param additional_targets: other addresses to send the same email
:param email_subject: optional title for email
"""
destination = ENDPOINTS.get(box_target, None)
if destination is None:
raise Exception('Target folder on Box does not exist')
recipients = [destination]
if additional_targets is not None:
recipients.extend(additional_targets)
subject = 'Updating files'
if email_subject is not None:
subject = email_subject
message = em.MIMEMultipart.MIMEMultipart()
message['From'] = 'user#domain.com'
message['To'] = ', '.join(recipients)
message['Date'] = em.Utils.formatdate(localtime=True)
message['Subject'] = subject
message.attach(em.MIMEText.MIMEText(body + '\n' +'Contents: \n{0}'.format('\n'.join(files))))
for f in files:
base = em.MIMEBase.MIMEBase('application', "octet-stream")
base.set_payload(open(f, 'rb').read())
em.Encoders.encode_base64(base)
base.add_header('Content-Disposition', 'attachment; filename={0}'.format(os.path.basename(f)))
message.attach(base)
conn = smtp.SMTP('smtp.gmail.com', 587)
un = 'user#gmail.com'
pw = 'test1234'
conn.starttls()
conn.login(un, pw)
conn.sendmail('user#domain.com', recipients, message.as_string())
conn.close()
I was facing the same issue, I fixed this issue now. Here is my code -
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import smtplib
import datetime
def sendMail():
message = MIMEMultipart()
message["To"] = "xxxxx#xxxx.com,yyyy#yyyy.com"
message["Cc"] = "zzzzzz#gmail.com,*********#gmail.com"
message["From"] = "xxxxxxxx#gmail.com"
message["Password"] = "***************"
server = 'smtp.gmail.com:587'
try:
now = datetime.datetime.now()
message['Subject'] = "cxxdRL Table status (Super Important Message) - "+str(now)
server = smtplib.SMTP(server)
server.ehlo()
server.starttls()
server.login(message["From"], message["Password"])
server.sendmail(message["From"], message["To"].split(",") + message["Cc"].split(","), message.as_string())
server.quit()
print('Mail sent')
except:
print('Something went wrong...')
sendMail()
I already programmed a function which sends mails with atachments, images on text and other things, but now I need the function to use de Cc (Carbon Copy) function in order to send copies to different emails.
I have done some changes on the function and it works but not as I want.
THe email is sent to the address ("toaddr") and the mail shows that there are other emails added as Cc("tocc") emails, but the Cc emails do not recieve the email.
To be more clear (because I think I am not being very clear) here is an example:
Sender: from#hotmail.com
Receiver: to#hotmail.com
Copied: cc#hotmail.com
to#hotmail.com receives the email and can see that cc#hotmail.com is copied on it.
cc#hotmail.com does not get the email.
if to#hotmail.com reply to all the email, THEN cc#hotmail gets the email.
Can anyone help me telling me what do I need to change on the function?? I guees the problem is with the server.sendmail() function
This is my function:
def enviarCorreo(fromaddr, toaddr, tocc, subject, text, file, imagenes):
msg = MIMEMultipart('mixed')
msg['From'] = fromaddr
msg['To'] = ','.join(toaddr)
msg['Cc'] = ','.join(tocc) # <-- I added this
msg['Subject'] = subject
msg.attach(MIMEText(text,'HTML'))
#Attached Images--------------
if imagenes:
imagenes = imagenes.split('--')
for i in range(len(imagenes)):
adjuntoImagen = MIMEBase('application', "octet-stream")
adjuntoImagen.set_payload(open(imagenes[i], "rb").read())
encode_base64(adjuntoImagen)
anexoImagen = os.path.basename(imagenes[i])
adjuntoImagen.add_header('Content-Disposition', 'attachment; filename= "%s"' % anexoImagen)
adjuntoImagen.add_header('Content-ID','<imagen_%s>' % (i+1))
msg.attach(adjuntoImagen)
#Files Attached ---------------
if file:
file = file.split('--')
for i in range(len(file)):
adjunto = MIMEBase('application', "octet-stream")
adjunto.set_payload(open(file[i], "rb").read())
encode_base64(adjunto)
anexo = os.path.basename(file[i])
adjunto.add_header('Content-Disposition', 'attachment; filename= "%s"' % anexo)
msg.attach(adjunto)
#Send ---------------------
server = smtplib.SMTP('localhost')
server.set_debuglevel(1)
server.sendmail(fromaddr,[toaddr,tocc], msg.as_string()) #<-- I modify this with the tocc
server.quit()
return
In your sendmail call, you're passing [toaddr, tocc] which is a list of lists, have you tried passing toaddr + tocc instead?