Collect multiple html files in a single email message - python

str_htmlHeader = "<!DOCTYPE HTML PUBLIC>\n<html>\n";
str_htmlHeader += "<head>\n\t<title>Audi Cloud Services</title>\n</head>\n\n";
str_htmlHeader += "<body>\n\n<h1>Nightly build test results</h1>\n";
str_htmlFooter = "\n</body>\n\n</html>";
for root, dirnames, filenames in os.walk(r'\\ac-srvfile01\_Embedded\VCon1\proj_customer\337159_Audi_ACR_and_TSSS\pcm-audio'):
for filename in fnmatch.filter(filenames, '*.html'):
reportContent = open(os.path.join(root,filename)).read()
attachment = MIMEText(str_htmlHeader+reportContent+str_htmlFooter, 'html')
msg.attach(attachment)
#msg.attach(MIMEText(open(filename).read(), "text/html"))
I am sending the message to a concerned person but the email is going to the respected person in a different email. I want to collect all the reports and send it as a single email. but the above code is sending the reports as a different email. Can someone help me how to fix that?

You want to create a single container message, then add MIME parts to it in the loop.
The multipart/alternative container is not suitable for this, as it indicates that the client should select one of the parts for display, and ignore the rest. I have used multipart/related instead. You could perhaps prefer multipart/mixed which does not imply a relationship of some sort between the parts.
str_htmlHeader = '''<!DOCTYPE HTML PUBLIC>
<html>
<head><title>Audvices</title></head>
<body><h1>Nightt results</h1>'''
str_htmlFooter = '''"
</body>\n\n</html>'''
msg = MIMEMultipart('related')
msg['From'] = 'ucd_test'
msg['To'] = 'hemappa#nce.com'
msg['Subject'] = 'AUDICES'
for root, dirnames, filenames in os.walk(r'\\ac-srvR_and_TSSS\pcm-audio'):
for filename in fnmatch.filter(filenames, '*.html'):
reportContent = open(os.path.join(root,filename)).read()
attachment = MIMEText(str_htmlHeader+reportContent+str_htmlFooter, 'html')
attachment.add_header("Content-Disposition", "attachment",\
filename=os.path.basename(filename))
msg.attach(attachment)
server = smtplib.SMTP('eu-smtp.nuance.com')
server.ehlo()
#server.starttls()
#server.login(username,password)
server.sendmail(fromaddress,toaddress.split(','),msg.as_string())
server.quit()

Related

Send multiple emails with different attachments each

I have a list of text files and html files generated by two distinct functions. Each file is labeled signal1.txt, signal2, etc. and signal1.html, signal2.html, etc. I need to send an email with each file pair (signal1.txt and signal1.html, signal2.txt and signal.2.html, and so forth). I've tried several different ways, but I keep getting just one file pair attached (the last file number whatever it is). I have no problem sending one file type, but it gets messy when I try with two different files.
Any help is appreciated. The code is as follows.
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email.mime.text import MIMEText
from email import encoders
import smtplib, ssl
import os
dirname = r'C:\Path\To\Files'
ext = ('.txt','html')
for files in os.scandir(dirname):
if files.path.endswith(ext):
def sendmail():
html_body = '''
<html>
<body>
<p style="font-size: 12;"> <strong>Alert</strong><br>{html}</p>
</body>
</html>
'''.format(html=html)
subject = f'Text file content'
senders_email = 'mail#mail.com'
receiver_email = 'mail#mail.com'
# Create a multipart message and set headers
message = MIMEMultipart('alternative')
message['From'] = senders_email
message['To'] = receiver_email
message['Subject'] = subject
#Attach email body
message.attach(MIMEText(html_body, 'html'))
# Name of the file to be attached
filename = f'signal.html'
# Open file in binary mode
with open(filename, 'rb') as attachment:
# Add file as application/octet-stream
part = MIMEBase('application', 'octet-stream')
part.set_payload(attachment.read())
# Encodes file in ASCII characters to send via email
encoders.encode_base64(part)
# Add header as key/value pair to attachment part
part.add_header(
'Content-Disposition',
f"attachment; filename= {filename}",
)
# Add attachment to message and convert message to string
message.attach(part)
text = message.as_string()
# Log into server using secure connection
context = ssl.create_default_context()
with smtplib.SMTP("smtp.mail.com", 25) as server:
# server.starttls(context=context)
# server.login(senders_email, 'password')
server.sendmail(senders_email, receiver_email, text)
print("Email sent!")
sendmail()
I've adapted one of these examples for your problem. This puts all the files in one email:
# Import smtplib for the actual sending function.
import smtplib
# Here are the email package modules we'll need.
from email.message import EmailMessage
import os
dirname = 'C:\Path\To\Files'
ext = ('.txt','html')
msg = EmailMessage()
msg['Subject'] = 'Text file content'
msg['From'] = 'mail#mail.com'
msg['To'] = 'mail#mail.com'
# Open the files in binary mode. You can also omit the subtype
# if you want MIMEImage to guess it.
for filename in os.scandir(dirname):
if filename.path.endswith(ext):
with open(filename, 'rb') as fp:
data = fp.read()
msg.add_attachment(data)
# Send the email via our own SMTP server.
with smtplib.SMTP('localhost') as s:
s.send_message(msg)
Found a way that worked using glob.
dirname = r'C:\Path\To\Files'
regex = create_txt_files(event_dict)
html_file = create_html_files(event_dict)
signalfiles = sorted(list(pathlib.Path(dirname).glob('*.txt')))
htmlfiles = sorted(list(pathlib.Path(dirname).glob('*.html')))
for i, path_html_file in enumerate(htmlfiles):
sendmail(html_file[i], regex[i], path_html_file)

smtplib multiple attachments failed to be received

I wrote a code that create a PDF, and I wanted to send it with another file (still a .pdf) with a python code based on SMTPLIB library.
You can see str(names[i]) value for the receiver email, since is taken from a table and also the sending-process is managed with a for cycle, were the name of the just-created pdf is depending on the str(names[i]) value.
I'm trying to manage the following code, considering a two factor authentication in order to send the automated email via python, from a gmail-based email:
sender_email = "sender#gmail.com"
receiver_email = str(names[i])
password = input("Authentication code: ")
subject = "Title"
body = """Hi,
This is the body of the email
"""
attachments = ['file1'+str(names[i])+'.pdf', 'file2.pdf'] # list of attachments
# Create a multipart message and set headers
message = MIMEMultipart()
message["From"] = sender_email
message["To"] = receiver_email
message["Subject"] = subject
message["Bcc"] = receiver_email # For mass emails
# Add body to email
message.attach(MIMEText(body, "plain"))
if 'attachments' in globals() and len('attachments') > 0:
for filename in attachments:
f = filename
part = MIMEBase('application', "octet-stream")
part.set_payload( open(f,"rb").read() )
encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(f))
message.attach(part)
# Add header as key/value pair to attachment part
part.add_header("Content-Disposition",f"attachment; filename= {attachments}",)
# Add attachment to message and convert message to string
message.attach(part)
text = message.as_string()
# Log in to server using secure context and send email
context = ssl.create_default_context()
with smtplib.SMTP_SSL("smtp.gmail.com", 465, context=context) as server:
server.login(sender_email, password)
server.sendmail(sender_email, receiver_email, text)
Everything works just fine: PDF is created, the mail is sent and received but.... the attachments are not ok in non-gmail emails.
What I find in the attachment list in a Outlook mail are files (with no extention) called ['file1'+str(names[i])+'.pdf', 'file2.pdf'], and trying with different receivers gives the same result.
It seems like non-gmail servers do not load files in the proper manner, while the gmail server recognizes the overall process
I thought about writing a "multiserver" object in the last with condition, but I don't know how to do it.
Thank you all!
In simplified code you do this:
# block#1 The following is simplified ---
for filename in attachments:
part = ... # construct part, include file content
part.add_header('Content-Disposition', ...)
message.attach(part)
# block#2: The following is original code ----
# Add header as key/value pair to attachment part
part.add_header("Content-Disposition",f"attachment; filename= {attachments}",)
# Add attachment to message and convert message to string
message.attach(part)
Thus, you
in block#1 you first create a part for each file
in block#2 you then take the last part from block#1 and add another content-disposition header, with including the name list as name
in block#2 you then attach this part again to this message
Obviously, block#1 is all you need and block#2 just messes up everything. Remove it.

Sending E-Mail to various recipients with Python

I want to send an email to various recipients (like 10 people) with the given table in the code, but the mail only reaches the first mail address. Is there a way to code it the way, that I can send an email to various recipients?
df = pd.DataFrame(Table)
filename = str(date.today()) + ".png"
#dir = pathlib.Path(__file__).parent.absolute()
folder = r"/results/"
#path_plot = str(dir) + folder + filename
from_mail = "abcdef#gmail.com"
to_mail = 'example1#hotmail.com,example2#live.com, example2#yahoo.com, example2#yahoo.de'
smtp_server = "smtp.gmail.com"
smtp_port = 465
def send_email( smtp_server, smtp_port, from_mail, from_password, to_mail):
'''
Send results
'''
msg = MIMEMultipart()
msg['Subject'] = 'Results'
msg['From'] = from_mail
COMMASPACE = ', '
msg['To'] = COMMASPACE.join([from_mail, to_mail])
msg.preamble = 'Something special'
html = """\
<html>
<head></head>
<body>
{0}
</body>
</html>
""".format(df.to_html())
part1 = MIMEText(html, 'html')
msg.attach(part1)
The to_addr argument should be a list of strings if you want to send to multiple recipients.
The immediate problem in your code is that you are joining the from_addr with the (string or list) to_addr where you should be creating a single list to put in the recipients field.
As an aside, your code seems to be written for Python 3.5 or earlier. The email library was overhauled in 3.6 and is now quite a bit more versatile and logical. Probably throw away what you have and start over with the examples from the email documentation.
Here is a basic refactoring (just quick and dirty; the structure is rather weird - why are you passing some strings as parameters whereas others are globals outside the function?). It removes some of the problems in your code simply because the modern API removes a lot of the boilerplate which was necessary with the older one.
import pandas as pd # I'm guessing ...?
from email.message import EmailMessage
...
df = pd.DataFrame(Table)
# Commenting out unused variables
# filename = str(date.today()) + ".png"
# folder = "/results/" # no need for an r string, no backslashes here
from_mail = "abcdef#gmail.com"
from_password = cred.passwort
to_mail = ['example1#hotmail.com', 'example2#live.com', 'example2#yahoo.com', 'example2#yahoo.de']
smtp_server = "smtp.gmail.com"
smtp_port = 465
def send_email(smtp_server, smtp_port, from_mail, from_password, to_mail):
'''
Send results via mail
'''
msg = EmailMessage()
msg['Subject'] = 'Results'
msg['From'] = from_mail
msg['To'] = ', '.join(to_mail + [from_mail])
# Don't muck with the preamble, especially if you don't understand what it is
html = """\
<html>
<head></head>
<body>
{0}
</body>
</html>
""".format(df.to_html())
msg.set_content(html, 'html')
with smtplib.SMTP_SSL(smtp_server, smtp_port) as server:
server.ehlo()
server.login(from_mail, from_password)
# Some servers require a second ehlo() here
# Use send_message instead of legacy sendmail method
server.send_message(msg)
server.quit()
send_email(smtp_server, smtp_port, from_mail, from_password, to_mail)
The generated HTML is still hideous but let's just hope nobody looks at the message source.

Attach CSV to E-Mail with MIMEBase, only attaches 'bin' document

I want to write a function to attach a csv file to an E-Mail with HTML text. Everything works fine. I sends the E-Mail with the text and the attachment with the right information. Only the data format is wrong. I tried different varieties in MIMEBASE('application', 'octet-stream'). This one gives me a '.bin' data which I cannot open on macOS. Others gave me a plain text data which included the right data, but I don't wanna copy it manually into a csv. Does someone have a solution how I get out the data as '.csv'? Most of the solutions I found here just looked like my code below.
Code:
def send_mail(receiver, subject, filepath, attachname):
#login information
port = 123
smtp_server = "test.server.com"
login = "testlogin" # your login
password = "12345678910" # your password
# specify the sender’s and receiver’s email addresses and text in HTML
sender = "testmail#test.com"
receiver = receiver
message = MIMEMultipart()
message["Subject"] = subject
message["From"] = sender
message["To"] = COMMASPACE.join([receiver])
html_text = """\
<html>
<body>
<p>Hi ,<br>
<p>kind regards</p>
<p> This is an automatized Mail </p>
</body>
</html>
"""
# convert both parts to MIMEText objects and add them to the MIMEMultipart message
text = MIMEText(html_text, "html")
message.attach(text)
#add a file as attachment
file = open(filepath, "rb")
att = MIMEBase('application', 'octet-stream')
att.set_payload(file.read())
encoders.encode_base64(att)
att.add_header("Content_Disposition",
'attachment', filename = attachname)
message.attach(att)
try:
#send your message with credentials specified above
with smtplib.SMTP(smtp_server, port) as server:
server.connect(smtp_server, port)
server.ehlo()
server.starttls()
server.ehlo()
server.login(login, password)
server.sendmail(sender, receiver, message.as_string())
# tell the script to report if your message was sent or which errors need to be fixed
print('Sent')
except (gaierror, ConnectionRefusedError):
print('Failed to connect to the server. Bad connection settings?')
except smtplib.SMTPServerDisconnected:
print('Failed to connect to the server. Wrong user/password?')
except smtplib.SMTPException as e:
print('SMTP error occurred: ' + str(e))
send_mail('testmail#test.com', 'TEST', '/Users/Changer/Desktop/test.csv', 'test.csv')
Email clients may use the content type of the attachment part to determine which program is used to open the attachment, so specifying a suitable content type may help.
This code uses the standard library's mimetypes module to try to guess the correct content type of the attachment, based on its name:
import mimetypes
mimetypes.init()
def send_mail(receiver, subject, filepath, attachname):
...
mimetype, _ = mimetypes.guess_type(attachname)
if mimetype is None:
mimetype = 'application/octet-stream'
type_, _, subtype = mimetype.partition('/')
att = MIMEBase(type_, subtype)
...
The above code will generate these headers for the attachment:
b'Content-Type: text/x-comma-separated-values'
b'MIME-Version: 1.0'
b'Content-Transfer-Encoding: base64'
b'Content_Disposition: attachment; filename="test.csv"'
Whether a mac will open a csv with a spreadsheet application (I assume this is what you want) depends on the configuration of the machine (See this blog for an example). If you want to be sure open the file in a spreadsheet it might be more effective to convert it to a spreadsheet format and send the spreadsheet.

Funny name/ Incomplete Attachment / wrong extension - Mail Python

I am sending mail from a linux box from a directory path which has three csv files. I want to attach all three in my email. Below is the script.
def mailer(sender, to, path):
msg = MIMEMultipart()
msg['Subject'] = 'UMR_EOD_RECONCILLATIONS'
msg['From'] = sender
msg['To'] = to
for file in os.listdir(path):
f = open( path + file, 'rb')
csv = MIMEText(f.read())
f.close()
msg.attach(csv)
mailer = smtplib.SMTP('localhost')
mailer.sendmail(sender,to, msg.as_string())
mailer.quit()
I have been scratching my head for a while and tried multiple times but still facing below issues.
The files which are attached are text files i.e. .txt extension, I want is to be csv
The files have funny names ATT00001.txt and ATT00002.txt which remains the same.
The third file is never attached to the mail it contents are outputted in the body and it's the damn same file however times I may try.
I have tried setting below but to no avail.
msg["Content-Disposition"] = "attachment; filename=" + file + ";"
msg.add_header('Content-Disposition', 'attachment', filename=file)
1) The first text object will be displayed as the email message. So, add an extra text object first.
2) CSV files should be transmitted as content-type: text/csv, not content-type: text/plain.
#UNTESTED
def mailer(sender, to, path):
msg = MIMEMultipart()
msg['Subject'] = 'UMR_EOD_RECONCILLATIONS'
msg['From'] = sender
msg['To'] = to
msg.attach(MIMEText('Here are the reports you asked for.'))
for file in os.listdir(path):
f = open( path + file, 'rb')
csv = MIMEText(f.read(), 'csv')
f.close()
csv.add_header('Content-Disposition', 'attachment', filename=file)
msg.attach(csv)
mailer = smtplib.SMTP('localhost')
mailer.sendmail(sender,to, msg.as_string())
mailer.quit()
I always advise to run from doing MIME stuff when you just want to send emails. I feel like no one wants to deal with that. It feels like Java.
Try yagmail; my apologies, I'm the developer.
Its purpose is to make it super easy to send emails with HTML, inline images and attachments.
The code for what you want:
import os
import yagmail
def mailer(sender, to, path):
yag = yagmail.SMTP(sender, host="localhost", smtp_skip_login=True)
contents = ['Here are the reports you asked for.'] + os.listdir(path)
yag.send(to, 'UMR_EOD_RECONCILLATIONS', contents)
I'd suggest to read the README for more nice tricks in there :)
To get started, use pip install yagmail to install yagmail.

Categories

Resources