python - por - ¿Cómo envío archivos adjuntos usando SMTP?
python send email gmail (6)
A continuación, le indicamos cómo enviar correos electrónicos con archivos adjuntos en un archivo zip y un cuerpo + cuerpo codificado en utf-8.
No fue sencillo descifrar esto, debido a la falta de documentación y muestras para este caso en particular.
Los caracteres que no son ASCII en la respuesta a deben codificarse, por ejemplo, con ISO-8859-1. Probablemente existe una función que puede hacer esto.
Propina:
Envíese un correo electrónico, guárdelo y examine el contenido para descubrir cómo hacer lo mismo en Python.
Aquí está el código, para 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=["[email protected]"],
subject="Test subject æøå",
body="Test body æøå",
zipfiles=[],
server="smtp.somewhere.xyz",
username="bob",
password="password123",
sender="Bob <[email protected]>",
replyto="=?ISO-8859-1?Q?M=F8=F8=F8?= <[email protected]>"): #: 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()
Quiero escribir un programa que envíe correo electrónico usando el smtplib de Python. Busqué en el documento y en los RFC, pero no pude encontrar nada relacionado con los archivos adjuntos. Por lo tanto, estoy seguro de que hay algún concepto de nivel superior que me estoy perdiendo. ¿Alguien me puede dar una idea de cómo funcionan los archivos adjuntos en SMTP?
Aquí hay un ejemplo de un mensaje con un archivo PDF adjunto, un "cuerpo" de texto y envío a través de 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''] = ''[email protected]''
msg[''To''] = ''[email protected]''
# 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(''[email protected]'',''xyzpassword'')
s.sendmail(''[email protected]'',[''[email protected]''], msg.as_string())
s.quit()
Aquí hay un ejemplo que saqué de una aplicación de trabajo que hicimos. Crea un correo electrónico HTML con un archivo adjunto de Excel.
import smtplib,email,email.encoders,email.mime.text,email.mime.base
smtpserver = ''localhost''
to = [''[email protected]'']
fromAddr = ''[email protected]''
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()
Bueno, los archivos adjuntos no se tratan de ninguna manera especial, son "solo" hojas del árbol de objetos de mensaje. Puede encontrar las respuestas a cualquier pregunta sobre mesasges compatibles con MIME en this sección de la documentación del paquete de email python.
En general, cualquier tipo de adjunto (leído: datos binarios sin procesar) se puede representar mediante el uso de la codificación Content-Transfer-Encoding
base64 (o similar).
Lo que quieres revisar es el módulo de email
. Le permite crear mensajes compatibles con MIME que luego envía con smtplib.
# -*- 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 = ''[email protected]''
PASS = ''yourpass''
FROM = ''[email protected]''
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()