I would like to ask for an advice for adding a zip option to the mailing script I am using for the delivery of reports.
I have email attachment limit set to 25MB and therefore some reports in json format that exceeds 25MB are dropped by the mailer script. I wanted to add a zip support that will compress the attachment if that is bigger than for ex. 15MB.
Below code is mailer part only.
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication
from email.mime.text import MIMEText
from email.utils import COMMASPACE
import sys
from os.path import basename
import argparse
import conf
import os
import zipfile
import zlib
###############################################################################
# Mailer function for server running environment
def send_mail(recipients, cc=None, subject=None, attachment=None, body=None, send_from=None):
msg = MIMEMultipart()
msg['Subject'] = subject
msg['From'] = send_from
msg['To'] = ','.join(recipients)
if cc:
msg['CC'] = ','.join(cc)
recipients.extend(cc)
if body:
text = MIMEText(body, 'html')
msg.attach(text)
if attachment:
with open(attachment, 'rb') as fp:
att = MIMEApplication(fp.read(), Name=basename(attachment))
att['Content-Disposition'] = f'attachment; filename="{basename(attachment)}"'
msg.attach(att)
smtp = smtplib.SMTP(conf.RELAY)
smtp.sendmail(send_from, recipients, msg.as_string())
smtp.quit()
Assuming the code you already have correctly attaches arbitrary attachments, including binary ones, then the following should zip up an attchment that is > 15M. If the original file's base name was, for example, test.dat, then the attachment archive name will be test.dat.zip and will contain test.dat as the single compressed file implicitly using zlib. No temporary files are needed for this as an in-memory buffer is used. So if the attachment is not outrageously large, this should be quite efficient:
if attachment:
MAX_ATTACHMENT_SIZE = 15 * 1024 * 1024
with open(attachment, 'rb') as fp:
bytes = fp.read()
attachment_name = basename(attachment)
if len(bytes) > MAX_ATTACHMENT_SIZE:
from io import BytesIO
buffer = BytesIO()
with zipfile.ZipFile(buffer, 'w', compression=zipfile.ZIP_DEFLATED) as zip_file:
zip_file.writestr(attachment_name, bytes)
# New attachment name and new data:
attachment_name += '.zip'
bytes = buffer.getvalue()
att = MIMEApplication(bytes, Name=attachment_name)
att['Content-Disposition'] = f'attachment; filename="{attachment_name}"'
msg.attach(att)
If you want to zip attacment, you can use the zipfile module to compress the file.
import zipfile
import tempfile
from email import encoders
from email.message import Message
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
...
if attachment:
zf = tempfile.TemporaryFile(prefix='mail', suffix='.zip')
zip = zipfile.ZipFile(zf, 'w')
zip.write(attachment)
zip.close()
zf.seek(0)
att = MIMEBase('application', 'zip')
att.set_payload(zf.read())
encoders.encode_base64(att)
att.add_header('Content-Disposition', 'attachment', filename=the_file + '.zip')
msg.attach(att)
...
Related
I'm trying to send email with attached image files and embedded image files inside a email body using HTML template, so far I can only attach image files but embedded image files doesn't appears in the mail . It says The link image cannot be displayed file may be removed, deleted or renamed. verify link point to correct image file and location and also files attached are of same size. below is the code which I used
import datetime
from requests_toolbelt import MultipartEncoder
import requests
import glob, os
import argparse
import smtplib
import base64
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication
from email.mime.image import MIMEImage
from os.path import basename
import os
import shutil
import socket
import ntpath
from jinja2 import Template
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
main = Template('''
<html><body>
{% for image in pictures %}<img src="cid:{{image}}">{% endfor %}
</body></html>''')
msg = MIMEMultipart()
html = main.render(pictures=files)
part2 = MIMEText(html, 'html')
msg.attach(part2)
msg['From'] = send_from
msg['To'] = ', '.join(send_to)
msg['Subject'] = subject
for f in files or []:
with open(f, "rb") as fil:
msgImage = MIMEImage(fil.read())
ext = f.split('.')[-1:]
attachedfile = MIMEApplication(fil.read(), _subtype = ext)
fil.close()
msgImage.add_header('Content-ID', '<{}>'.format(f))
msgImage.add_header('content-Disposition','inline',filename=f)
msg.attach(msgImage)
attachedfile.add_header(
'content-disposition', 'attachment', filename=basename(f) )
msg.attach(msgImage)
msg.attach(attachedfile)
smtp = smtplib.SMTP(host="smtp-mail.outlook.com", port= 25)
smtp.starttls()
smtp.login(usr,pwd)
smtp.sendmail(send_from, send_to, msg.as_string())
smtp.close()
send_mail(send_from= frommail,
subject="Daily backup Testing",
text='files added: ',
send_to= tomail,
files= files_list)
I get mail as this . Image path files are correct. when I print I get this files ['check123\\Screenshot (161).png', 'check123\\Screenshot (163).png', 'check123\\Screenshot (164).png']
I don't know where I'm doing wrong , If the file path is wrong it should've given error while reading file itself fil.read(). Can anyone point me the mistake in my code? thanks
I would like to create a text file in Python, write something to it, and then e-mail it out (put test.txt as an email attachment).
However, I cannot save this file locally. Does anyone know how to go about doing this?
As soon as I open the text file to write in, it is saved locally on my computer.
f = open("test.txt","w+")
I am using smtplib and MIMEMultipart to send the mail.
StringIO is the way to go...
from email import encoders
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
from io import StringIO
email = MIMEMultipart()
email['Subject'] = 'subject'
email['To'] = 'recipient#example.com'
email['From'] = 'sender#example.com'
# Add the attachment to the message
f = StringIO()
# write some content to 'f'
f.write("content for 'test.txt'")
f.seek(0)
msg = MIMEBase('application', "octet-stream")
msg.set_payload(f.read())
encoders.encode_base64(msg)
msg.add_header('Content-Disposition',
'attachment',
filename='test.txt')
email.attach(msg)
I found this post while figuring out how to do this with the newer EmailMessage, which was introduced in Python 3.6 (see https://docs.python.org/3/library/email.message.html). It's slightly less code:
from email.message import EmailMessage
from io import StringIO
from smtplib import SMTP
message = EmailMessage()
message['Subject'] = 'Subject'
message['From'] = 'from#example.com'
message['To'] = 'to#example.com'
f = StringIO()
f.name = 'attachment.txt'
f.write('contents of file')
f.seek(0)
message.add_attachment(f.read(), filename=f.name)
with SMTP('yourmailserver.com', 25) as server:
server.send_message(message)
Good Afternoon.
I would like to know how to reference files or a folder to a variable in Python.
Lets say i have some files with the following names:
161225_file1.txt
161225_file2.txt
161225_file3.txt
161226_file1.txt
161226_file2.txt
161226_file3.txt
161227_file1.txt
161227_file2.txt
161227_file3.txt
i want to assign those files to a variable so i can use it in a email script i have, i also only need the files with a certain date.
Right now i only have the following:
#!/usr/bin/env python
###############################
#Imports (some library imports)
###############################
import sys
import time
import os
import re
from datetime import date,timedelta
from lib.osp import Connection
from lib.sendmail import *
###############################
#Parameters (some parameters i`ll use to send the email, like the email body message with yesterdays date)
###############################
ndays = 1
yesterday = date.today() - timedelta(days=ndays)
address = 'some.email#gmail.com'
title = '"Email Test %s"' % yesterday
attachments = ''
mail_body = "This is a random message with yesterday`s date %s" % yesterday
###############################
#Paths (Path that contain the home directory and the directory of the files i want to attach)
###############################
homedir = '/FILES/user/emails/'
filesdir = '/FILES/user/emails/TestFolder/'
###############################
#Script
###############################
#starts the mail function
start_mail()
#whatever message enters here will be in the email`s body.
write_mail(mail_body)
#gets everything you did before this step and sends it vial email.
send_mail(address,title,attachments)
os.listdir() will get files and subdirectories in a directory.
If you want just files,use os.path:
from os import listdir
from os.path import isfile, join
files = [f for f in listdir(homedir) if isfile(join(homedir, f))]
And you can find detailed explantion on how to attach file to an email here
Thanks to Oli
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)
)
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()
import smtplib
from email.MIMEMultipart import MIMEMultipart
from email.MIMEText import MIMEText
from email.MIMEImage import MIMEImage
msg = MIMEMultipart('multipart/related')
fromaddr = 'from#gmail.com'
toaddrs = 'to#gmail.com'
#provide gmail user name and password
username = 'to#gmail.com'
password = 'messifan'
filename = "1.jpg"
f = file(filename)
attachment = MIMEImage(f.read()) # error here
attachment.add_header('Content-Disposition', 'attachment', filename=filename)
.
.
server.sendmail(fromaddr, toaddrs, msg.as_string())
i am using this code to send email. i can attach text file using this script.(chenging MIMEImage to MIMEtext). but cannot attach image. the error is Could not guess Image mime subtype
Try
attachment = MIMEImage(f.read(), _subtype="jpeg") # error here
a bit of a guess here, but maybe try opening the file in binary mode?
f = file(filename, 'rb')
Looks to me like you created a "file" object, but you never opened it.
Where you have:
f = file(filename)
attachment = MIMEImage(f.read()) # error here
I think you instead need:
fp = open(filename, 'rb')
attachment = MIMEImage(fp.read())
fp.close()
I would like to compress a folder and all its sub-folders/files, and email the zip file as an attachment. What would be the best way to achieve this with Python?
You can use the zipfile module to compress the file using the zip standard, the email module to create the email with the attachment, and the smtplib module to send it - all using only the standard library.
Python - Batteries Included
If you don't feel like programming and would rather ask a question on stackoverflow.org instead, or (as suggested in the comments) left off the homework tag, well, here it is:
import smtplib
import zipfile
import tempfile
from email import encoders
from email.message import Message
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
def send_file_zipped(the_file, recipients, sender='you#you.com'):
zf = tempfile.TemporaryFile(prefix='mail', suffix='.zip')
zip = zipfile.ZipFile(zf, 'w')
zip.write(the_file)
zip.close()
zf.seek(0)
# Create the message
themsg = MIMEMultipart()
themsg['Subject'] = 'File %s' % the_file
themsg['To'] = ', '.join(recipients)
themsg['From'] = sender
themsg.preamble = 'I am not using a MIME-aware mail reader.\n'
msg = MIMEBase('application', 'zip')
msg.set_payload(zf.read())
encoders.encode_base64(msg)
msg.add_header('Content-Disposition', 'attachment',
filename=the_file + '.zip')
themsg.attach(msg)
themsg = themsg.as_string()
# send the message
smtp = smtplib.SMTP()
smtp.connect()
smtp.sendmail(sender, recipients, themsg)
smtp.close()
"""
# alternative to the above 4 lines if you're using gmail
server = smtplib.SMTP_SSL('smtp.gmail.com', 465)
server.login("username", "password")
server.sendmail(sender,recipients,themsg)
server.quit()
"""
With this function, you can just do:
send_file_zipped('result.txt', ['me#me.org'])
You're welcome.
Look at zipfile for compressing a folder and it's subfolders.
Look at smtplib for an email client.
You can use zipfile that ships with python, and here you can find an example of sending an email with attachments with the standard smtplib