2009-12-27 19 views
19

Quiero escribir un programa que envía correo electrónico utilizando Python smtplib. Busqué a través del documento y las 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. ¿Puede alguien darme una pista sobre cómo funcionan los archivos adjuntos en SMTP?¿Cómo envío archivos adjuntos usando SMTP?

+3

Para que quede claro, no hay nada en absoluto en SMTP para manejar esto, es completamente manejado por la estructuración del documento que se envía como un documento MIME. El artículo sobre MIME en wikipedia parece cubrir bastante bien el básico. – jcoder

+3

La inclusión de un enlace directo a los "ejemplos de correo electrónico" de la documentación de Python haría que cualquier respuesta completa: http://docs.python.org/library/email-examples.html –

Respuesta

10

Lo que se quiere revisar es el módulo email. Le permite crear MIME -compliant mensajes que luego envía con smtplib.

+1

Gracias para la edición, que eran un poco más rápido que yo ;-) –

3

Bueno, accesorios no son tratados de cualquier manera especial, son "sólo" hojas del árbol mensaje a objetos. Puede encontrar las respuestas a cualquier pregunta con respecto mesasges compatible con MIME en this sección de la documentación en el paquete email pitón.

En general, cualquier tipo de archivo adjunto (léase: datos binarios en bruto) puede representarse utilizando base64 (o similar) Content-Transfer-Encoding.

18

He aquí un ejemplo que corté 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() 
+6

el subtipo de varias partes debe ser 'mixta' en lugar de 'alternativo' de lo contrario no podrá ver el archivo adjunto en algunos clientes de correo electrónico. – rhyek

3

Así es como enviar correos electrónicos con archivos adjuntos zip y UTF-8 sujetos codificada + cuerpo.

No fue sencillo para la forma de saberlo, debido a la falta de documentación y muestras para este caso particular.

caracteres no ASCII en replyto necesita ser codificada con, por ejemplo, ISO-8859-1. Probablemente exista una función que puede hacer esto.

Consejo:
enviamos un correo electrónico, guardarlo y examinar el contenido de averiguar 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() 
28

Aquí es un ejemplo de un mensaje con un archivo PDF adjunto, un texto "cuerpo" y el 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() 
+2

Esto resolvió mi problema para correo electrónico archivos de Excel, así que era increíble porque me mantuvo fuera de os.system llamando Rubí! Gracias Kevin! – Benjooster

+0

Esta solución también trabajó para mí, después de crear un archivo de .xls utilizando el módulo xlwt Python. En lugar de enviar por Gmail, utilicé el servidor de correo de mi compañía. Gracias, y +1 –

+0

este método realmente funcionó y es mucho más limpio. –

1
# -*- 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() 
Cuestiones relacionadas