Come posso inviare gli allegati utilizzando il protocollo SMTP?
-
21-09-2019 - |
Domanda
Voglio scrivere un programma che invia e-mail utilizzando Python smtplib . Ho cercato attraverso il documento e le RFC, ma non ho trovato tutto ciò che riguarda gli allegati. Così, sono sicuro che ci sia un concetto di livello superiore che sto perdendo. Può qualcuno indizio me in su come attrezzi di lavoro in SMTP?
Soluzione
Che cosa si vuole verificare è il modulo email
. Esso consente di costruire MIME messaggi -compatibile che poi inviati con smtplib.
Altri suggerimenti
Ecco un esempio di un messaggio con un allegato PDF, un testo "corpo" e l'invio tramite Gmail.
# Import smtplib for the actual sending function
import smtplib
# For guessing MIME type
import mimetypes
# Import the email modules we'll need
import email
import email.mime.application
# Create a text/plain message
msg = email.mime.Multipart.MIMEMultipart()
msg['Subject'] = 'Greetings'
msg['From'] = 'xyz@gmail.com'
msg['To'] = 'abc@gmail.com'
# The main body is just another attachment
body = email.mime.Text.MIMEText("""Hello, how are you? I am fine.
This is a rather nice letter, don't you think?""")
msg.attach(body)
# PDF attachment
filename='simple-table.pdf'
fp=open(filename,'rb')
att = email.mime.application.MIMEApplication(fp.read(),_subtype="pdf")
fp.close()
att.add_header('Content-Disposition','attachment',filename=filename)
msg.attach(att)
# send via Gmail server
# NOTE: my ISP, Centurylink, seems to be automatically rewriting
# port 25 packets to be port 587 and it is trashing port 587 packets.
# So, I use the default port 25, but I authenticate.
s = smtplib.SMTP('smtp.gmail.com')
s.starttls()
s.login('xyz@gmail.com','xyzpassword')
s.sendmail('xyz@gmail.com',['xyz@gmail.com'], msg.as_string())
s.quit()
Ecco un esempio che tagliò fuori da una domanda di lavoro che abbiamo fatto. Si crea una e-mail HTML con un allegato di Excel.
import smtplib,email,email.encoders,email.mime.text,email.mime.base
smtpserver = 'localhost'
to = ['email@somewhere.com']
fromAddr = 'automated@hi.com'
subject = "my subject"
# create html email
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>...</p>'
html += "</body></html>"
emailMsg = email.MIMEMultipart.MIMEMultipart('alternative')
emailMsg['Subject'] = subject
emailMsg['From'] = fromAddr
emailMsg['To'] = ', '.join(to)
emailMsg['Cc'] = ", ".join(cc)
emailMsg.attach(email.mime.text.MIMEText(html,'html'))
# now attach the file
fileMsg = email.mime.base.MIMEBase('application','vnd.ms-excel')
fileMsg.set_payload(file('exelFile.xls').read())
email.encoders.encode_base64(fileMsg)
fileMsg.add_header('Content-Disposition','attachment;filename=anExcelFile.xls')
emailMsg.attach(fileMsg)
# send email
server = smtplib.SMTP(smtpserver)
server.sendmail(fromAddr,to,emailMsg.as_string())
server.quit()
Bene, gli allegati non sono trattati in alcun modo speciale, sono "solo" foglie dell'albero Message-oggetto. È possibile trovare le risposte alle domande relative mesasges MIME-compliant in questa sezione della documentazione sul package email python.
In generale, qualsiasi tipo di attacco (leggi: dati binari grezzi) può essere rappresentato utilizzando base64
(O simili) Content-Transfer-Encoding
.
Ecco come inviare e-mail con allegati di file ZIP e utf-8 soggetti codificato + corpo.
Non è stato semplice per capirci qualcosa, a causa della mancanza di documentazione ed esempi per questo caso particolare.
caratteri non ASCII in replyto deve essere codificato con, per esempio, ISO-8859-1. Esiste probabilmente una funzione che può fare questo.
Suggerimento:.
Invia anche tu una e-mail, salvare e esaminare il contenuto di capire come fare la stessa cosa in Python
Ecco il codice, per Python 3:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# vim:set ts=4 sw=4 et:
from os.path import basename
from smtplib import SMTP
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
from email.header import Header
from email.utils import parseaddr, formataddr
from base64 import encodebytes
def send_email(recipients=["somebody@somewhere.xyz"],
subject="Test subject æøå",
body="Test body æøå",
zipfiles=[],
server="smtp.somewhere.xyz",
username="bob",
password="password123",
sender="Bob <bob@somewhere.xyz>",
replyto="=?ISO-8859-1?Q?M=F8=F8=F8?= <bob@somewhere.xyz>"): #: bool
"""Sends an e-mail"""
to = ",".join(recipients)
charset = "utf-8"
# Testing if body can be encoded with the charset
try:
body.encode(charset)
except UnicodeEncodeError:
print("Could not encode " + body + " as " + charset + ".")
return False
# Split real name (which is optional) and email address parts
sender_name, sender_addr = parseaddr(sender)
replyto_name, replyto_addr = parseaddr(replyto)
sender_name = str(Header(sender_name, charset))
replyto_name = str(Header(replyto_name, charset))
# Create the message ('plain' stands for Content-Type: text/plain)
try:
msgtext = MIMEText(body.encode(charset), 'plain', charset)
except TypeError:
print("MIMEText fail")
return False
msg = MIMEMultipart()
msg['From'] = formataddr((sender_name, sender_addr))
msg['To'] = to #formataddr((recipient_name, recipient_addr))
msg['Reply-to'] = formataddr((replyto_name, replyto_addr))
msg['Subject'] = Header(subject, charset)
msg.attach(msgtext)
for zipfile in zipfiles:
part = MIMEBase('application', "zip")
b = open(zipfile, "rb").read()
# Convert from bytes to a base64-encoded ascii string
bs = encodebytes(b).decode()
# Add the ascii-string to the payload
part.set_payload(bs)
# Tell the e-mail client that we're using base 64
part.add_header('Content-Transfer-Encoding', 'base64')
part.add_header('Content-Disposition', 'attachment; filename="%s"' %
os.path.basename(zipfile))
msg.attach(part)
s = SMTP()
try:
s.connect(server)
except:
print("Could not connect to smtp server: " + server)
return False
if username:
s.login(username, password)
print("Sending the e-mail")
s.sendmail(sender, recipients, msg.as_string())
s.quit()
return True
def main():
send_email()
if __name__ == "__main__":
main()
# -*- coding: utf-8 -*-
"""
Mail sender
"""
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import smtplib
import pystache
import codecs
import time
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
HOST = 'smtp.exmail.qq.com'
PORT = 587
USER = 'your@mail.com'
PASS = 'yourpass'
FROM = 'your@mail.com'
SUBJECT = 'subject'
HTML_NAME = 'tpl.html'
CSV_NAME = 'list.txt'
FAILED_LIST = []
def send(mail_receiver, mail_to):
# text = mail_text
html = render(mail_receiver)
# msg = MIMEMultipart('alternative')
msg = MIMEMultipart('mixed')
msg['From'] = FROM
msg['To'] = mail_to.encode()
msg['Subject'] = SUBJECT.encode()
# msg.attach(MIMEText(text, 'plain', 'utf-8'))
msg.attach(MIMEText(html, 'html', 'utf-8'))
try:
_sender = smtplib.SMTP(
HOST,
PORT
)
_sender.starttls()
_sender.login(USER, PASS)
_sender.sendmail(FROM, mail_to, msg.as_string())
_sender.quit()
print "Success"
except smtplib.SMTPException, e:
print e
FAILED_LIST.append(mail_receiver + ',' + mail_to)
def render(name):
_tpl = codecs.open(
'./html/' + HTML_NAME,
'r',
'utf-8'
)
_html_string = _tpl.read()
return pystache.render(_html_string, {
'receiver': name
})
def main():
ls = open('./csv/' + CSV_NAME, 'r')
mail_list = ls.read().split('\r')
for _receiver in mail_list:
_tmp = _receiver.split(',')
print 'Mail: ' + _tmp[0] + ',' + _tmp[1]
time.sleep(20)
send(_tmp[0], _tmp[1])
print FAILED_LIST
main()