Làm thế nào để gửi tệp đính kèm email?


282

Tôi gặp vấn đề trong việc hiểu cách gửi email tệp đính kèm bằng Python. Tôi đã gửi email thành công các tin nhắn đơn giản với smtplib. Ai đó có thể vui lòng giải thích làm thế nào để gửi một tập tin đính kèm trong một email. Tôi biết có những bài viết khác trực tuyến nhưng là một người mới bắt đầu Python tôi thấy chúng khó hiểu.


5
Đây là một triển khai đơn giản có thể đính kèm nhiều tệp và thậm chí tham chiếu đến chúng trong trường hợp hình ảnh được nhúng. datamakessense.com/...
AdrianBR

Tôi tìm thấy drupal.org/project/mimemail/issues/911612 hữu ích này hóa ra các tệp đính kèm hình ảnh cần phải được gắn vào một phần con loại liên quan. Nếu bạn đính kèm hình ảnh vào phần MIME gốc, hình ảnh có thể hiển thị trong danh sách các mục được đính kèm và được xem trước trong các máy khách như triển vọng365.
Hinchy

@AdrianBR nếu tôi có một hình ảnh dưới dạng tệp PDF. Png có vấn đề về pixel khi phóng to nên png không tốt cho tôi.
Pinocchio

Câu trả lời:


415

Đây là một:

import smtplib
from os.path import basename
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.utils import COMMASPACE, formatdate


def send_mail(send_from, send_to, subject, text, files=None,
              server="127.0.0.1"):
    assert isinstance(send_to, list)

    msg = MIMEMultipart()
    msg['From'] = send_from
    msg['To'] = COMMASPACE.join(send_to)
    msg['Date'] = formatdate(localtime=True)
    msg['Subject'] = subject

    msg.attach(MIMEText(text))

    for f in files or []:
        with open(f, "rb") as fil:
            part = MIMEApplication(
                fil.read(),
                Name=basename(f)
            )
        # After the file is closed
        part['Content-Disposition'] = 'attachment; filename="%s"' % basename(f)
        msg.attach(part)


    smtp = smtplib.SMTP(server)
    smtp.sendmail(send_from, send_to, msg.as_string())
    smtp.close()

Nó giống như ví dụ đầu tiên ... Nhưng nó sẽ dễ dàng thả vào hơn.


7
Hãy cẩn thận với các mặc định có thể thay đổi: stackoverflow.com/questions/101268/hidden-features-of-python/
mẹo

11
@ user589983 Tại sao không đề xuất chỉnh sửa như bất kỳ người dùng nào khác ở đây? Tôi đã thay đổi tham chiếu còn lại filethành f.
Oli

9
Lưu ý cho các nhà phát triển Python3: mô-đun "email.Utils" đã được đổi tên thành "email.utils"
gecco

6
thay cho python2.5 + sử dụng MIMEApplication dễ dàng hơn - giảm ba dòng đầu tiên của vòng lặp xuống:part = MIMEApplication(open(f, 'rb').read())
mata

5
Chủ đề không được hiển thị trong email gửi. Chỉ hoạt động sau khi thay đổi dòng thành thông điệp ['Chủ đề'] = chủ đề. Tôi sử dụng trăn 2.7.
Lu-ca

70

Đây là phiên bản sửa đổi từ Olicho python 3

import smtplib
from pathlib import Path
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email.mime.text import MIMEText
from email.utils import COMMASPACE, formatdate
from email import encoders


def send_mail(send_from, send_to, subject, message, files=[],
              server="localhost", port=587, username='', password='',
              use_tls=True):
    """Compose and send email with provided info and attachments.

    Args:
        send_from (str): from name
        send_to (list[str]): to name(s)
        subject (str): message title
        message (str): message body
        files (list[str]): list of file paths to be attached to email
        server (str): mail server host name
        port (int): port number
        username (str): server auth username
        password (str): server auth password
        use_tls (bool): use TLS mode
    """
    msg = MIMEMultipart()
    msg['From'] = send_from
    msg['To'] = COMMASPACE.join(send_to)
    msg['Date'] = formatdate(localtime=True)
    msg['Subject'] = subject

    msg.attach(MIMEText(message))

    for path in files:
        part = MIMEBase('application', "octet-stream")
        with open(path, 'rb') as file:
            part.set_payload(file.read())
        encoders.encode_base64(part)
        part.add_header('Content-Disposition',
                        'attachment; filename="{}"'.format(Path(path).name))
        msg.attach(part)

    smtp = smtplib.SMTP(server, port)
    if use_tls:
        smtp.starttls()
    smtp.login(username, password)
    smtp.sendmail(send_from, send_to, msg.as_string())
    smtp.quit()

cảm ơn nhưng thật tuyệt khi cũng có cơ bản: cú pháp cho một tệp đính kèm (sử dụng đường dẫn của nó)
JinSnow

Có vẻ như bạn không đóng các tệp của mình, đó sẽ là rác được thu thập hoặc đóng khi thoát nhưng đó là thói quen xấu. với open () như f: là cách đúng.
comte

Mã không hoạt động. Tên biến f sai trong định dạng (os.path.basename (f)) phải là định dạng (os.path.basename (đường dẫn))
Chris

1
send_to nên được liệt kê [str]
Subin

2
câu trả lời tốt nhất cho tôi nhưng có một lỗi nhỏ: thay thế import pathlibbằngfrom pathlib import Path
AleAve81

65

đây là mã tôi đã sử dụng:

import smtplib
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email import Encoders


SUBJECT = "Email Data"

msg = MIMEMultipart()
msg['Subject'] = SUBJECT 
msg['From'] = self.EMAIL_FROM
msg['To'] = ', '.join(self.EMAIL_TO)

part = MIMEBase('application', "octet-stream")
part.set_payload(open("text.txt", "rb").read())
Encoders.encode_base64(part)

part.add_header('Content-Disposition', 'attachment; filename="text.txt"')

msg.attach(part)

server = smtplib.SMTP(self.EMAIL_SERVER)
server.sendmail(self.EMAIL_FROM, self.EMAIL_TO, msg.as_string())

Mã giống như bài của Oli. Cảm ơn tất cả

Mã dựa trên bài đăng tệp đính kèm email nhị phân .


2
Câu trả lời tốt. Sẽ rất tuyệt nếu nó cũng chứa mã có thêm một văn bản cơ thể mẫu.
Steven Bluen 17/03/2015

4
Xin lưu ý, trong các bản phát hành hiện đại của thư viện email - việc nhập mô-đun là khác nhau. ví dụ:from email.mime.base import MIMEBase
Varun Balupuri

27
from email.MIMEMultipart import MIMEMultipart
from email.MIMEText import MIMEText
from email.MIMEImage import MIMEImage
import smtplib

msg = MIMEMultipart()
msg.attach(MIMEText(file("text.txt").read()))
msg.attach(MIMEImage(file("image.png").read()))

# to send
mailer = smtplib.SMTP()
mailer.connect()
mailer.sendmail(from_, to, msg.as_string())
mailer.close()

Chuyển thể từ đây .


Không hoàn toàn những gì tôi đang tìm kiếm. Các tập tin đã được gửi dưới dạng cơ thể của một email. Ngoài ra còn có các dấu ngoặc bị thiếu trên dòng 6 và 7. Tôi cảm thấy rằng chúng ta đang tiến gần hơn
Richard

2
Email là văn bản đơn giản, và đó là những gì smtplibhỗ trợ. Để gửi tệp đính kèm, bạn mã hóa chúng dưới dạng tin nhắn MIME và gửi chúng trong email văn bản gốc. Tuy nhiên, có một mô-đun email python mới: docs.python.org/l Library / email.mime.html
Katriel

@katrienlalex một ví dụ hoạt động sẽ giúp tôi hiểu hơn
Richard

1
Bạn có chắc chắn ví dụ trên không hoạt động? Tôi không có máy chủ SMTP tiện dụng, nhưng tôi đã xem msg.as_string()và nó chắc chắn trông giống như cơ thể của một email nhiều phần MIME. Wikipedia giải thích MIME: en.wikipedia.org/wiki/MIME
Katriel

1
Line 6, in <module> msg.attach(MIMEText(file("text.txt").read())) NameError: name 'file' is not defined
Benjamin2002

7

Một cách khác với python 3 (Nếu ai đó đang tìm kiếm):

import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders

fromaddr = "sender mail address"
toaddr = "receiver mail address"

msg = MIMEMultipart()

msg['From'] = fromaddr
msg['To'] = toaddr
msg['Subject'] = "SUBJECT OF THE EMAIL"

body = "TEXT YOU WANT TO SEND"

msg.attach(MIMEText(body, 'plain'))

filename = "fileName"
attachment = open("path of file", "rb")

part = MIMEBase('application', 'octet-stream')
part.set_payload((attachment).read())
encoders.encode_base64(part)
part.add_header('Content-Disposition', "attachment; filename= %s" % filename)

msg.attach(part)

server = smtplib.SMTP('smtp.gmail.com', 587)
server.starttls()
server.login(fromaddr, "sender mail password")
text = msg.as_string()
server.sendmail(fromaddr, toaddr, text)
server.quit()

Đảm bảo cho phép các ứng dụng kém an toàn hơn trên ứng dụng Gmail trên tài khoản Gmail của bạn


6

Phiên bản Gmail, hoạt động với Python 3.6 (lưu ý rằng bạn sẽ cần thay đổi cài đặt Gmail của mình để có thể gửi email qua smtp từ nó:

import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication
from os.path import basename


def send_mail(send_from: str, subject: str, text: str, 
send_to: list, files= None):

    send_to= default_address if not send_to else send_to

    msg = MIMEMultipart()
    msg['From'] = send_from
    msg['To'] = ', '.join(send_to)  
    msg['Subject'] = subject

    msg.attach(MIMEText(text))

    for f in files or []:
        with open(f, "rb") as fil: 
            ext = f.split('.')[-1:]
            attachedfile = MIMEApplication(fil.read(), _subtype = ext)
            attachedfile.add_header(
                'content-disposition', 'attachment', filename=basename(f) )
        msg.attach(attachedfile)


    smtp = smtplib.SMTP(host="smtp.gmail.com", port= 587) 
    smtp.starttls()
    smtp.login(username,password)
    smtp.sendmail(send_from, send_to, msg.as_string())
    smtp.close()

Sử dụng:

username = 'my-address@gmail.com'
password = 'top-secret'
default_address = ['my-address2@gmail.com'] 

send_mail(send_from= username,
subject="test",
text="text",
send_to= None,
files= # pass a list with the full filepaths here...
)

Để sử dụng với bất kỳ nhà cung cấp email nào khác, chỉ cần thay đổi cấu hình smtp.


4

Mã đơn giản nhất tôi có thể nhận được là:

#for attachment email
from django.core.mail import EmailMessage

    def attachment_email(request):
            email = EmailMessage(
            'Hello', #subject
            'Body goes here', #body
            'MyEmail@MyEmail.com', #from
            ['SendTo@SendTo.com'], #to
            ['bcc@example.com'], #bcc
            reply_to=['other@example.com'],
            headers={'Message-ID': 'foo'},
            )

            email.attach_file('/my/path/file')
            email.send()

Nó được dựa trên tài liệu chính thức của Django


3
trong trường hợp của bạn, bạn phải cài đặt django để gửi email ... nó không trả lời đúng câu hỏi
comte

@comte 'coz python chỉ được sử dụng cho Django, phải không?
Auspex

5
@Auspex đó là quan điểm của tôi ;-) giống như cài đặt LibreScript để chỉnh sửa tệp cấu hình ...
comte

Tôi thấy điều này hữu ích và nhiều thông tin. chỉ có một mô-đun được nhập khẩu và việc sử dụng nó khá đơn giản và thanh lịch so với các vòng MIME mà người khác nhảy qua. Trong ví dụ của bạn, ngược lại, LibreOffice khó sử dụng hơn notepad.
Người hâm mộ số một của Bjork

4

Các câu trả lời khác là tuyệt vời, mặc dù tôi vẫn muốn chia sẻ một cách tiếp cận khác trong trường hợp ai đó đang tìm kiếm giải pháp thay thế.

Sự khác biệt chính ở đây là sử dụng phương pháp này, bạn có thể sử dụng HTML / CSS để định dạng thư của mình, do đó bạn có thể sáng tạo và đưa ra một số kiểu dáng cho email của mình. Mặc dù bạn không bắt buộc sử dụng HTML, bạn vẫn có thể chỉ sử dụng văn bản thuần túy.

Lưu ý rằng chức năng này chấp nhận gửi email đến nhiều người nhận và cũng cho phép đính kèm nhiều tệp.

Tôi mới chỉ thử cái này trên Python 2, nhưng tôi nghĩ nó cũng hoạt động tốt trên cả 3:

import os.path
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication

def send_email(subject, message, from_email, to_email=[], attachment=[]):
    """
    :param subject: email subject
    :param message: Body content of the email (string), can be HTML/CSS or plain text
    :param from_email: Email address from where the email is sent
    :param to_email: List of email recipients, example: ["a@a.com", "b@b.com"]
    :param attachment: List of attachments, exmaple: ["file1.txt", "file2.txt"]
    """
    msg = MIMEMultipart()
    msg['Subject'] = subject
    msg['From'] = from_email
    msg['To'] = ", ".join(to_email)
    msg.attach(MIMEText(message, 'html'))

    for f in attachment:
        with open(f, 'rb') as a_file:
            basename = os.path.basename(f)
            part = MIMEApplication(a_file.read(), Name=basename)

        part['Content-Disposition'] = 'attachment; filename="%s"' % basename
        msg.attach(part)

    email = smtplib.SMTP('your-smtp-host-name.com')
    email.sendmail(from_email, to_email, msg.as_string())

Tôi hi vọng cái này giúp được! :-)


2
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
import smtplib
import mimetypes
import email.mime.application

smtp_ssl_host = 'smtp.gmail.com'  # smtp.mail.yahoo.com
smtp_ssl_port = 465
s = smtplib.SMTP_SSL(smtp_ssl_host, smtp_ssl_port)
s.login(email_user, email_pass)


msg = MIMEMultipart()
msg['Subject'] = 'I have a picture'
msg['From'] = email_user
msg['To'] = email_user

txt = MIMEText('I just bought a new camera.')
msg.attach(txt)

filename = 'introduction-to-algorithms-3rd-edition-sep-2010.pdf' #path to file
fo=open(filename,'rb')
attach = email.mime.application.MIMEApplication(fo.read(),_subtype="pdf")
fo.close()
attach.add_header('Content-Disposition','attachment',filename=filename)
msg.attach(attach)
s.send_message(msg)
s.quit()

Để giải thích, bạn có thể sử dụng liên kết này, nó giải thích chính xác https://medium.com/@sdoshi579/to-send-an-email-along-with-attachment-USE-smtp-7852e77623


2
from email.mime.multipart import MIMEMultipart
from email.mime.image import MIMEImage
from email.mime.text import MIMEText
import smtplib

msg = MIMEMultipart()

password = "password"
msg['From'] = "from_address"
msg['To'] = "to_address"
msg['Subject'] = "Attached Photo"
msg.attach(MIMEImage(file("abc.jpg").read()))
file = "file path"
fp = open(file, 'rb')
img = MIMEImage(fp.read())
fp.close()
msg.attach(img)
server = smtplib.SMTP('smtp.gmail.com: 587')
server.starttls()
server.login(msg['From'], password)
server.sendmail(msg['From'], msg['To'], msg.as_string())
server.quit()

2
xin chào, xin chào, xin vui lòng luôn gửi lời giải thích về câu trả lời của bạn khi trả lời câu hỏi để hiểu rõ hơn
Ali

0

Dưới đây là sự kết hợp của những gì tôi đã tìm thấy từ bài đăng của Soccererer ở đây và liên kết sau giúp tôi dễ dàng đính kèm tệp xlsx hơn. Tìm thấy ở đây

file = 'File.xlsx'
username=''
password=''
send_from = ''
send_to = 'recipient1 , recipient2'
Cc = 'recipient'
msg = MIMEMultipart()
msg['From'] = send_from
msg['To'] = send_to
msg['Cc'] = Cc
msg['Date'] = formatdate(localtime = True)
msg['Subject'] = ''
server = smtplib.SMTP('smtp.gmail.com')
port = '587'
fp = open(file, 'rb')
part = MIMEBase('application','vnd.ms-excel')
part.set_payload(fp.read())
fp.close()
encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment', filename='Name File Here')
msg.attach(part)
smtp = smtplib.SMTP('smtp.gmail.com')
smtp.ehlo()
smtp.starttls()
smtp.login(username,password)
smtp.sendmail(send_from, send_to.split(',') + msg['Cc'].split(','), msg.as_string())
smtp.quit()

0

Với mã của tôi, bạn có thể gửi tệp đính kèm email bằng gmail, bạn sẽ cần:

đặt địa chỉ gmail của bạn tại " EMAIL SMTP CỦA BẠN TẠI ĐÂY "

đặt mật khẩu tài khoản gmail của bạn tại " PASSWORD SMTP CỦA BẠN TẠI ĐÂY_ "

Trong phần ___EMAIL ĐỂ NHẬN phần MESSAGE_ bạn cần đặt địa chỉ email đích.

Thông báo báo động là chủ đề,

Có người đã vào phòng, hình ảnh đính kèm là thi thể.

["/home/pi/webcam.jpg"] là tệp đính kèm hình ảnh.

#!/usr/bin/env python
import smtplib
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email.Utils import COMMASPACE, formatdate
from email import Encoders
import os

USERNAME = "___YOUR SMTP EMAIL HERE___"
PASSWORD = "__YOUR SMTP PASSWORD HERE___"

def sendMail(to, subject, text, files=[]):
    assert type(to)==list
    assert type(files)==list

    msg = MIMEMultipart()
    msg['From'] = USERNAME
    msg['To'] = COMMASPACE.join(to)
    msg['Date'] = formatdate(localtime=True)
    msg['Subject'] = subject

    msg.attach( MIMEText(text) )

    for file in files:
        part = MIMEBase('application', "octet-stream")
        part.set_payload( open(file,"rb").read() )
        Encoders.encode_base64(part)
        part.add_header('Content-Disposition', 'attachment; filename="%s"'
                       % os.path.basename(file))
        msg.attach(part)

    server = smtplib.SMTP('smtp.gmail.com:587')
    server.ehlo_or_helo_if_needed()
    server.starttls()
    server.ehlo_or_helo_if_needed()
    server.login(USERNAME,PASSWORD)
    server.sendmail(USERNAME, to, msg.as_string())
    server.quit()

sendMail( ["___EMAIL TO RECEIVE THE MESSAGE__"],
        "Alarm notification",
        "Someone has entered the room, picture attached",
        ["/home/pi/webcam.jpg"] )

Lâu rồi không gặp! Thật tốt khi thấy rằng bạn đang gán đúng mã của mình và đưa nó trực tiếp vào câu trả lời. Tuy nhiên, nó thường cau mày khi sao chép-dán cùng một mã câu trả lời cho nhiều câu hỏi. Nếu chúng thực sự có thể được giải quyết bằng cùng một giải pháp, bạn nên gắn cờ các câu hỏi dưới dạng trùng lặp .
Das_Geek

0

Bạn cũng có thể chỉ định loại tệp đính kèm bạn muốn trong e-mail của mình, như một ví dụ tôi đã sử dụng pdf:

def send_email_pdf_figs(path_to_pdf, subject, message, destination, password_path=None):
    ## credits: http://linuxcursor.com/python-programming/06-how-to-send-pdf-ppt-attachment-with-html-body-in-python-script
    from socket import gethostname
    #import email
    from email.mime.application import MIMEApplication
    from email.mime.multipart import MIMEMultipart
    from email.mime.text import MIMEText
    import smtplib
    import json

    server = smtplib.SMTP('smtp.gmail.com', 587)
    server.starttls()
    with open(password_path) as f:
        config = json.load(f)
        server.login('me@gmail.com', config['password'])
        # Craft message (obj)
        msg = MIMEMultipart()

        message = f'{message}\nSend from Hostname: {gethostname()}'
        msg['Subject'] = subject
        msg['From'] = 'me@gmail.com'
        msg['To'] = destination
        # Insert the text to the msg going by e-mail
        msg.attach(MIMEText(message, "plain"))
        # Attach the pdf to the msg going by e-mail
        with open(path_to_pdf, "rb") as f:
            #attach = email.mime.application.MIMEApplication(f.read(),_subtype="pdf")
            attach = MIMEApplication(f.read(),_subtype="pdf")
        attach.add_header('Content-Disposition','attachment',filename=str(path_to_pdf))
        msg.attach(attach)
        # send msg
        server.send_message(msg)

nguồn cảm hứng / tín dụng đến: http://linuxcthon.com/python-programming/06-how-to-send-pdf-ppt-attachment-with-html-body-in-python-script

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.