Как отправлять вложения с помощью SMTP?

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

Ответ 1

Что вы хотите проверить, это модуль email. Он позволяет вам создавать MIME -соответствующие сообщения, которые вы затем отправляете с smtplib.

Ответ 2

Вот пример сообщения с вложением PDF, текст "тело" и отправка через 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()

Ответ 3

Вот пример, который я вырвал из рабочего приложения, которое мы сделали. Он создает электронную почту HTML с вложением 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()

Ответ 4

Ну, вложения не обрабатываются никакими специальными способами, они являются "просто" листьями дерева Message-object. Вы можете найти ответы на любые вопросы относительно MIME-совместимых mesasges в этом разделе документации по email пакет python.

В общем, любое вложение (чтение: необработанные двоичные данные) может быть представлено с помощью base64 (или аналогичный) Content-Transfer-Encoding.

Ответ 5

Здесь, как отправлять сообщения электронной почты с вложенными файлами в zip файле и закодированным объектом utf-8 + body.

Нелегко было понять это из-за отсутствия документации и образцов для этого конкретного случая.

Символы non-ascii в ответе должны быть закодированы, например, ISO-8859-1. Вероятно, существует функция, которая может это сделать.

Совет.
Отправьте электронное письмо, сохраните его и просмотрите содержимое, чтобы выяснить, как сделать то же самое в Python.

Здесь код для 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()

Ответ 6

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