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()
Related
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)
...
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 am using the following program to send an email with pdf attachments. The program runs successfully and I get the email with the attachments, but when I use a task scheduler to run the program, I get the email with the body but no attachments. What could be the reason? I need this program to run and send out the email at 7 pm each day. Is there another way to get the program to run at a specific time without using the task scheduler?
Following is my program:
import smtplib
import os
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email import encoders
from os import path
from glob import glob
email_user = '#sender address#'
email_send = '#reciever address#'
subject = 'Subject'
msg = MIMEMultipart()
msg['From'] = email_user
msg['To'] = email_send
msg['Subject'] = subject
body = "Hello:\nPlease find attached the reports"
msg.attach(MIMEText(body, 'plain'))
path = (r'''#path of the files to be attached''')
files = [f for f in os.listdir(path) if os.path.isfile(f)]
filenames = filter(lambda f: f.endswith(('.pdf','.PDF')), files)
for filename in filenames:
attachment = open(filename, 'rb')
part = MIMEBase('application', 'octet-stream')
part.set_payload((attachment).read())
encoders.encode_base64(part)
part.add_header('Content-Disposition',"attachment; filename =
"+filename)
msg.attach(part)
text = msg.as_string()
server = smtplib.SMTP('smtp.gmail.com',587)
server.starttls()
server.login(email_user,'#password#')
server.sendmail(email_user,email_send,text)
server.quit()
os.listdir strips the path information, so this script will only work when the working directory is the same as the one in "path". Your task scheduler is apparently not working there. So you need to provide the full path:
path = (r'''#path of the files to be attached''')
files = [os.path.join(path, f) for f in os.listdir(path)]
files = filter(os.path.isfile, files)
I see you imported glob but you don't use it. That would be the best way to go, since it returns the full path AND it can do the extension filtering. You can make it case insensitive like this:
files = glob(os.path.join(path, '*.[pD][dD][fF]'))
I have got some code to attach files from an email using MIME module
however each time I send the email I want it to automatically send
only the first 5 most recent pictures in the file.
import os, re
import sys
import smtplib
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
SMTP_SERVER = 'smtp.gmail.com'
SMTP_PORT = 587
sender = '***#gmail.com'
password = "*******"
recipient = '***#gmail.com'
subject = 'Python emaillib Test'
message = 'Images attached.'
directory = "images/"
def main():
msg = MIMEMultipart()
msg['Subject'] = 'Python emaillib Test'
msg['To'] = recipient
msg['From'] = sender
#this is where it searches for the image
files = os.listdir(directory)
jpgsearch = re.compile(".jpg", re.IGNORECASE)
files = filter(jpgsearch.search, files)
for filename in files:
path = os.path.join(directory, filename)
if not os.path.isfile(path):
continue
img = MIMEImage(open(path, 'rb').read(), _subtype="jpg")
img.add_header('Content-Disposition', 'attachment', filename = filename)
msg.attach(img)
part = MIMEText('text', "plain")
part.set_payload(message)
msg.attach(part)
session = smtplib.SMTP(SMTP_SERVER, SMTP_PORT)
session.ehlo()
session.starttls()
session.ehlo
session.login(sender, password)
session.sendmail(sender, recipient, msg.as_string())
session.quit()
if __name__ == '__main__':
main()
I am a beginner to Python so help would be appreciated
Use os.stat to fetch atime, ctime or mtime. Then simple compare timestamps (or use some other logic based on datetime.datetime.fromtimestamp)
I need to figure out how to make a script that scans for new files in a directory, and when there is a new one, sends the file via email.
Someone keeps stealing bikes in my apartment building! First it was my fault (I for got to lock it), now the crook upgraded by cutting chains. I had it after the crook stole my second bike by cutting 1/2 inch airplane wire.
Anyway, using a raspberry pi as a motion activated security camera, I want it to send me a video file as soon as the video program finishes recording it. This is incase they steal the pi.
I am looking at these examples, but I can't figure how to make the script run continuously (every minute) or how to make it scan a folder for a new file.
How do I send attachments using SMTP?
OK
I got it down to scanning and then trying to email. It fails when trying to attach the video file. Can you help? Here is the revised code:
The failure is:
msg = MIMEMultipart()
TypeError: 'LazyImporter' object is not callable, line 38
import time, glob
import smtplib
import email.MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email.Utils import COMMASPACE, formatdate
from email import Encoders, MIMEMultipart
import os
#Settings:
fromemail= "Jose Garcia <somerandomemail#gmail.com>"
loginname="somerandomemail#gmail.com"
loginpassword="somerandomepassword"
toemail= "Jose Garcia <somerandomemail#gmail.com>"
SMTPserver='smtp.gmail.com'
SMTPort=587
fileslocation="/Users/someone/Desktop/Test/*.mp4"
subject="Security Notification"
def mainloop():
files=glob.glob(fileslocation) #Put whatever path and file format you're using in there.
while 1:
new_files=glob.glob(fileslocation)
if len(new_files)>len(files):
for x in new_files:
if x in files:
print("New file detected "+x)
print("about to call send email")
sendMail(loginname, loginpassword, toemail, fromemail, subject, gethtmlcode(), x, SMTPserver, SMTPort)
files=new_files
time.sleep(1)
def sendMail(login, password, to, frome, subject, text, filee, server, port):
# assert type(to)==list
# assert type(filee)==list
msg = MIMEMultipart()
msg['From'] = frome
msg['To'] = COMMASPACE.join(to)
msg['Date'] = formatdate(localtime=True)
msg['Subject'] = subject
msg.attach( MIMEText(text) )
# #for filee in files:
part = MIMEBase('application', "octet-stream")
part.set_payload( open(filee,"rb").read() )
Encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment; filename="%s"'
% os.path.basename(filee))
msg.attach(part)
smtp = smtplib.SMTP(SMTPserver, SMTPort)
smtp.sendmail(frome, to, msg.as_string() )
server.set_debuglevel(1)
server.starttls()
server.ehlo()
server.login(login, password)
server.sendmail(frome, to, msg)
server.quit()
def gethtmlcode():
print("about to assemble html")
html = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" '
html +='"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml">'
html +='<body style="font-size:12px;font-family:Verdana"><p>A new video file has been recorded </p>'
html += "</body></html>"
return(html)
#Execute loop
mainloop()
I finally got it working. I had to use python 2.5 to get rid of the LazyImporter error. Every time a new file is added to the security folder, it gets emailed to me. Logging is broken.
import time, glob
import smtplib
from email.MIMEMultipart import MIMEMultipart
from email.MIMEMultipart import MIMEBase
from email.MIMEText import MIMEText
from email.Utils import COMMASPACE, formatdate
import datetime
from email import Encoders
import os
import sys
#Settings:
fromemail= 'RaspberryPI Security Camera <someone>'
loginname='someone#gmail.com'
loginpassword='something'
toemail= 'Jose Garcia < someone#gmail.com>'
SMTPserver='smtp.gmail.com'
SMTPort=587
fileslocation='/Users/someone/Desktop/Test/*.*'
subject="Security Notification"
log='logfile.txt'
def mainloop():
files=glob.glob(fileslocation) #Put whatever path and file format you're using in there.
while 1:
f = open(log, 'w')
sys.stdout = Tee(sys.stdout, f)
new_files=glob.glob(fileslocation)
if len(new_files)>len(files):
for x in new_files:
if x in files:
print(str(datetime.datetime.now()) + "New file detected "+x)
sendMail(loginname, loginpassword, toemail, fromemail, subject, gettext(), x, SMTPserver, SMTPort)
files=new_files
f.close()
time.sleep(1)
def sendMail(login, password, send_to, send_from, subject, text, send_file, server, port):
msg = MIMEMultipart()
msg['From'] = send_from
msg['To'] = COMMASPACE.join(send_to)
msg['Date'] = formatdate(localtime=True)
msg['Subject'] = subject
msg.attach( MIMEText(text) )
part = MIMEBase('application', "octet-stream")
part.set_payload( open(send_file,"rb").read() )
Encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(send_file))
msg.attach(part)
smtp = smtplib.SMTP(SMTPserver, SMTPort)
smtp.set_debuglevel(1)
smtp.ehlo()
smtp.starttls()
smtp.login(login, password)
smtp.sendmail(send_from, send_to, msg.as_string() )
smtp.close()
def gettext():
text = "A new file has been added to the security footage folder. \nTime Stamp: "+ str(datetime.datetime.now())
return(text)
class Tee(object):
def __init__(self, *files):
self.files = files
def write(self, obj):
for f in self.files:
f.write(obj)
#Execute loop
mainloop()
It looks like the email module has been refactored over time. This fixed the 'LazyImporter' object not callable error for me on Python 2.7:
from email.mime.text import MIMEText
Noteably it was not happy with (what I thought were) synonyms like import email; email.mime.text.MIMEText(...)
I use python3 and I could not for the life of me get any of these examples to work, but I was able to come up with something that works and is a whole lot simpler.
import smtplib
from email.message import EmailMessage
from email.mime.base import MIMEBase
from email import encoders
# Defining Objects and Importing Files ------------------------------------
# Initializing video object
video_file = MIMEBase('application', "octet-stream")
# Importing video file
video_file.set_payload(open('video.mkv', "rb").read())
# Encoding video for attaching to the email
encoders.encode_base64(video_file)
# creating EmailMessage object
msg = EmailMessage()
# Loading message information ---------------------------------------------
msg['From'] = "person_sending#gmail.com"
msg['To'] = "person_receiving#gmail.com"
msg['Subject'] = 'text for the subject line'
msg.set_content('text that will be in the email body.')
msg.add_attachment(video_file, filename="video.mkv")
# Start SMTP Server and sending the email ---------------------------------
server=smtplib.SMTP_SSL('smtp.gmail.com',465)
server.login("person_sending#gmail.com", "some-clever-password")
server.send_message(msg)
server.quit()
Just put your script in a loop and have it sleep for 60 seconds. You can use glob to get a list of files in the directory. in is pretty useful for seeing what is in a list (i.e. the list of files in the directory).
import time, glob
files=glob.glob("/home/me/Desktop/*.mp4") #Put whatever path and file format you're using in there.
while 1:
new_files=glob.glob("/home/me/Desktop/*.mp4")
if len(new_files)>len(files):
for x in new_files:
if x not in files:
print("New file: "+x) #This is where you would email it. Let me know if you need help figuring that out.
files=new_files
time.sleep(60)