2009-12-27 51 views
19

Tôi muốn viết chương trình gửi email bằng cách sử dụng smtplib của Python. Tôi đã tìm kiếm thông qua tài liệu và RFC, nhưng không thể tìm thấy bất kỳ thứ gì liên quan đến tệp đính kèm. Vì vậy, tôi chắc chắn có một số khái niệm cấp cao hơn tôi đang bỏ lỡ. Ai đó có thể gợi ý cho tôi về cách các tệp đính kèm hoạt động trong SMTP không?Làm cách nào để gửi tệp đính kèm bằng SMTP?

+3

Chỉ cần được rõ ràng, không có gì ở tất cả trong SMTP để xử lý này là, nó hoàn toàn xử lý bởi cơ cấu lại các tài liệu được gửi đi như một tài liệu MIME. Bài viết về MIME trên wikipedia dường như bao gồm các cơ bản khá tốt. – jcoder

+3

Bao gồm liên kết trực tiếp đến phần "ví dụ email" của tài liệu Python sẽ làm cho mọi câu trả lời hoàn tất: http://docs.python.org/library/email-examples.html –

Trả lời

10

Điều bạn muốn kiểm tra là mô-đun email. Nó cho phép bạn xây dựng các thông báo MIME -compliant mà bạn gửi với smtplib.

+1

Cảm ơn bạn đã chỉnh sửa, bạn đã nhanh hơn một chút so với I ;-) –

3

Vâng, tệp đính kèm không được xử lý theo bất kỳ cách đặc biệt nào, chúng chỉ là "lá" của cây đối tượng Tin nhắn. Bạn có thể tìm thấy câu trả lời cho bất kỳ câu hỏi nào về các mesasges tuân thủ MIME trong phần this của tài liệu trên gói python email.

Nói chung, bất kỳ loại tệp đính kèm nào (đọc: dữ liệu nhị phân thô) có thể được biểu diễn bằng cách sử dụng base64 (hoặc tương tự) Content-Transfer-Encoding.

18

Đây là một ví dụ tôi đã loại bỏ một ứng dụng công việc mà chúng tôi đã làm. Nó tạo ra một email HTML với một tập tin đính kèm 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

Loại phụ nhiều nên được 'trộn' thay vì 'thay thế' nếu không bạn sẽ không thấy tệp đính kèm trong một số ứng dụng email. – rhyek

3

Dưới đây là cách gửi e-mail kèm theo tệp đính kèm zip và chủ đề được mã hóa utf-8 + body.

Nó không phải là đơn giản để con số này ra, do thiếu tài liệu và mẫu cho trường hợp cụ thể này.

Các ký tự không phải ascii trong thư trả lời cần được mã hóa, ví dụ: ISO-8859-1. Có thể tồn tại một chức năng có thể làm điều này.

Mẹo:
Gửi cho chính bạn một e-mail, lưu và kiểm tra nội dung để tìm ra cách thực hiện tương tự trong Python.

Dưới đây là đoạn code, cho 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

Dưới đây là một ví dụ về một tin nhắn với một tập tin đính kèm PDF, một văn bản "cơ thể" và gửi qua 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

Điều này đã giải quyết được vấn đề của tôi đối với việc gửi email các tệp excel, điều này thật tuyệt vời vì nó đã giúp tôi thoát khỏi os.system gọi Ruby! Cảm ơn Kevin! – Benjooster

+0

Giải pháp này cũng làm việc cho tôi, sau khi tạo tệp .xls bằng mô-đun Python xlwt. Thay vì gửi qua Gmail, tôi đã sử dụng máy chủ thư của công ty mình. Cảm ơn và +1 –

+0

phương pháp này thực sự hiệu quả và sạch hơn nhiều! –

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() 
Các vấn đề liên quan