Как отправить вложения электронной почты?

283

У меня проблемы с пониманием того, как отправить вложение с помощью Python. Я успешно отправил простые сообщения по электронной почте smtplib. Может кто-нибудь объяснить, пожалуйста, как отправить вложение в электронном письме. Я знаю, что есть другие посты в сети, но как начинающий Python, я нахожу их трудно понять.

Ричард
источник
5
Вот простая реализация, которая может прикреплять несколько файлов и даже ссылаться на них в случае вставляемых изображений. datamakessense.com/…
AdrianBR
Я обнаружил, что этот полезный drupal.org/project/mimemail/issues/911612 оказывается, что вложения изображений должны быть прикреплены к дочерней части связанного типа. Если вы прикрепите изображение к корневой части MIME, изображения могут отображаться в списке прикрепленных элементов и просматриваться на клиентах, таких как outlook365.
Хинчи
@AdrianBR, что если у меня есть изображение в виде файла PDF. У PNG есть проблемы с пикселями при масштабировании, так что PNG не подходят для меня.
Буратино

Ответы:

416

Вот еще один:

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()

Это почти так же, как в первом примере ... Но это должно быть проще.

Oli
источник
7
Будьте осторожны с изменяемыми значениями по умолчанию: stackoverflow.com/questions/101268/hidden-features-of-python/…
Gringo Suave
11
@ user589983 Почему бы не предложить редактирование, как это сделал бы любой другой пользователь? Я изменил оставшуюся ссылку на fileв f.
Оли
9
Примечание для разработчиков на Python3: модуль "email.Utils" был переименован в "email.utils"
gecco
7
для python2.5 + проще использовать MIMEApplication - сокращает первые три строки цикла до:part = MIMEApplication(open(f, 'rb').read())
mata
5
Тема не была показана в электронном письме. Работает только после изменения строки на msg ['Subject'] = subject. Я использую Python 2.7.
Лука
70

Вот модифицированная версия Oliдля 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()
Эхсан Иран-Неджад
источник
спасибо, но было бы неплохо также иметь основной: синтаксис для одного прикрепленного файла (используя его путь)
JinSnow
кажется, что вы не закрываете свои файлы, это будет сборка мусора или закрытие на выходе, но это плохая привычка. с open (), так как f: правильный путь.
конт
Код не работает. Неверное имя переменной f в формате (os.path.basename (f)) должно быть в формате (os.path.basename (путь))
Крис
1
send_to должен быть в списке [str]
Subin
2
лучший ответ для меня, но есть небольшая ошибка: заменить import pathlibнаfrom pathlib import Path
AleAve81
65

это код, который я в конечном итоге использовал:

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())

Код во многом такой же, как и у Оли. Спасибо всем

Код основан на сообщении о проблеме с вложением в двоичный файл .

Ричард
источник
2
Хороший ответ. Было бы хорошо, если бы он также содержал код, который добавляет образец основного текста.
Стивен Блюен
4
Обратите внимание, что в современных выпусках библиотеки электронной почты - импорт модулей различен. Например:from email.mime.base import MIMEBase
Варун Балупури
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()

Адаптировано отсюда .

Oli
источник
Не совсем то, что я ищу. Файл был отправлен как тело письма. Существует также отсутствуют скобки на линии 6 и 7. Я чувствую , что мы становимся ближе , хотя
Richard
2
Письма в виде простого текста, и это то, что smtplibподдерживает. Чтобы отправить вложения, вы кодируете их как сообщение MIME и отправляете их в виде обычного электронного письма. Тем не менее, есть новый почтовый модуль Python: docs.python.org/library/email.mime.html
Катриэль
@katrienlalex рабочий пример мог бы помочь мне понять
Ричард
1
Вы уверены, что приведенный выше пример не работает? У меня нет удобного SMTP-сервера, но я посмотрел, msg.as_string()и он, безусловно, выглядит как тело многочастной электронной почты MIME. Википедия объясняет MIME: en.wikipedia.org/wiki/MIME
Катриэль
1
Line 6, in <module> msg.attach(MIMEText(file("text.txt").read())) NameError: name 'file' is not defined
Benjamin2002
7

Другой способ с питоном 3 (если кто-то ищет):

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()

Убедитесь, что в вашей учетной записи Gmail разрешены « менее безопасные приложения »

Sudarshan
источник
6

Версия Gmail, работающая с Python 3.6 (обратите внимание, что вам нужно будет изменить настройки Gmail, чтобы иметь возможность отправлять с него электронную почту через smtp:

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()

Использование:

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...
)

Чтобы использовать его с любым другим почтовым провайдером, просто измените настройки SMTP.

Ferrarezi
источник
4

Простейший код, который я смог получить:

#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()

Это было основано на официальной документации Django

Андраде
источник
3
в вашем случае вы должны установить django, чтобы отправить электронное письмо ... он не отвечает должным образом на вопрос
comte
@comte 'coz python используется только для Django, верно?
Auspex
5
@Auspex это моя точка ;-) это как установку LibreOffice для редактирования конфигурационного файла ...
конт
Я считаю это полезным и информативным. импортируется только один модуль, и его использование довольно простое и элегантное по сравнению с MIME-хопами, через которые прыгают другие. В вашем примере, напротив, LibreOffice сложнее в использовании, чем блокнот.
питта
4

Другие ответы превосходны, хотя я все еще хотел поделиться другим подходом на случай, если кто-то ищет альтернативы.

Основное отличие здесь заключается в том, что используя этот подход, вы можете использовать HTML / CSS для форматирования вашего сообщения, чтобы вы могли проявить творческий подход и придать стиль своей электронной почте. Хотя вы не обязаны использовать HTML, вы также можете использовать только простой текст.

Обратите внимание, что эта функция принимает отправку электронной почты нескольким получателям, а также позволяет прикреплять несколько файлов.

Я только пробовал это на Python 2, но я думаю, что он должен работать на 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())

Надеюсь, это поможет! :-)

Антоний Фуэнтес Артавиа
источник
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()

Для объяснения вы можете использовать эту ссылку, которую он объясняет должным образом https://medium.com/@sdoshi579/to-send-an-email-along-with-attachment-using-smtp-7852e77623

sdoshi
источник
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
привет, добро пожаловать, пожалуйста, всегда
Али
0

Ниже приведена комбинация того, что я нашел в посте SoccerPlayer Здесь и следующей ссылки, которая облегчила мне прикрепление файла xlsx. Нашел здесь

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()
TonyRyan
источник
0

С моим кодом вы можете отправлять вложения электронной почты, используя gmail, вам необходимо:

установите свой адрес электронной почты на « ВАШ SMTP E-mail ЗДЕСЬ »

установите пароль своей учетной записи Gmail на " ВАШ SMTP ПАРОЛЬ ЗДЕСЬ_ "

В части ___EMAIL TO RECEIVE THE MESSAGE_ вам необходимо указать адрес электронной почты получателя.

Тревожное уведомление является темой,

Кто-то вошел в комнату, изображение прикреплено к телу

["/home/pi/webcam.jpg"] является вложением изображения.

#!/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"] )
Джон Руа
источник
Давно не виделись! Приятно видеть, что вы правильно приписываете свой код и включаете его непосредственно в ответ. Однако обычно неодобрительно копировать и вставлять один и тот же код ответа на несколько вопросов. Если их действительно можно решить одним и тем же решением, вы должны пометить вопросы как дубликаты .
Das_Geek
0

Вы также можете указать тип вложения, который вы хотите в вашей электронной почте, в качестве примера я использовал 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)

вдохновение / кредиты: http://linuxcursor.com/python-programming/06-how-to-send-pdf-ppt-attachment-with-html-body-in-python-script

Пиноккио
источник