Як надсилати вкладення електронною поштою?


283

У мене виникають проблеми з розумінням того, як відправити вкладення електронною поштою за допомогою Python. Я успішно надсилав по електронній пошті прості повідомлення з smtplib. Невже хтось може пояснити, як надіслати вкладення електронною поштою. Я знаю, що в Інтернеті є й інші публікації, але як початківець Python мені важко зрозуміти.


5
ось проста реалізація, яка може приєднати кілька файлів і навіть посилатися на них у випадку вбудовування зображень. datamakessense.com/…
AdrianBR

Я вважаю це корисним drupal.org/project/mimemail/isissue/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()

Це майже те саме, що і перший приклад ... Але впасти треба легше.


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'] = тема. Я використовую 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: це правильний шлях.
comte

Код не працює. Неправильне ім'я змінної f у форматі (os.path.basename (f)) має бути форматом (os.path.basename (path))
Кріс,

1
send_to повинен бути список [str]
Субін

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

Адаптований звідси .


Не зовсім те, що я шукаю. Файл надіслано як тіло електронного листа. Дуже відсутні дужки на рядках 6 та 7. Я відчуваю, що ми все ближче
Річард

2
Електронні листи - це звичайний текст, і саме це smtplibпідтримує. Щоб надсилати вкладені файли, ви кодуєте їх як MIME-повідомлення та надсилаєте їх електронним листом у відкритому тексті. Однак є новий електронний модуль python: docs.python.org/library/email.mime.html
Katriel

@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
Бенджамін2002,

7

Ще один спосіб за допомогою python 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


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.


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

Він базувався на офіційній документації Джанго


3
у вашому випадку вам потрібно встановити django, щоб надіслати електронний лист ... він не відповідає належним чином на запитання
comte

@comte 'coz python використовується коли-небудь для Django, правда?
Auspex

5
@Auspex - це моя думка ;-) це як встановити LibreOffice для редагування конфігураційного файлу ...
comte

Я вважаю це корисним та інформативним. імпортується лише один модуль, і його використання досить просте та елегантне порівняно з обручами 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


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

0

За допомогою мого коду ви можете надсилати вкладення електронною поштою за допомогою gmail:

встановіть свою gmail адресу на " ВАШЕ SMTP EMAIL ТУТ "

встановіть пароль свого облікового запису gmail на " ВАШ ПАРТМЕР SMTP ТУТ_ "

У частині ___EMAIL ДЛЯ ВИПУСКУВАННЯ ПОВІДОМЛЕННЯ_ вам потрібно встановити цільову електронну адресу.

Повідомлення про тривогу є предметом,

Хтось увійшов до кімнати, прикріплене зображення - тіло

["/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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.