【问题标题】:How do I send attachments using SMTP?如何使用 SMTP 发送附件?
【发布时间】:2010-12-30 06:43:00
【问题描述】:

我想编写一个使用 Python 的smtplib 发送电子邮件的程序。我搜索了文档和 RFC,但找不到与附件相关的任何内容。因此,我确信我错过了一些更高层次的概念。有人能告诉我附件在 SMTP 中是如何工作的吗?

【问题讨论】:

  • 要明确一点,SMTP 中根本没有任何东西可以处理这个问题,它完全是通过将要发送的文档构造为 MIME 文档来处理的。维基百科上关于 MIME 的文章似乎很好地涵盖了基本知识。
  • 包含直接指向 Python 文档“电子邮件示例”部分的链接将使任何答案都完整:docs.python.org/library/email-examples.html
  • 我相信@PeterHansen 的链接已移至docs.python.org/3/library/email.examples.html

标签: python email smtp attachment smtplib


【解决方案1】:

这是一个带有 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'] = 'xyz@gmail.com'
msg['To'] = 'abc@gmail.com'

# 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('xyz@gmail.com','xyzpassword')
s.sendmail('xyz@gmail.com',['xyz@gmail.com'], msg.as_string())
s.quit()

【讨论】:

  • 这也解决了我通过电子邮件发送 excel 文件的问题,这太棒了,因为它让我无法使用 os.system 调用 Ruby!谢谢凯文!
  • 在使用 Python xlwt 模块创建 .xls 文件后,此解决方案也适用于我。我没有通过 Gmail 发送,而是使用了我公司的邮件服务器。谢谢,+1
  • 这个方法确实有效,而且更干净!
  • 在这里工作!谢谢凯文
  • 添加标题(在 python2.7.9 中)没有正确命名文件。我的解决方法是将行更改为:att.add_header('Content-Disposition', 'attachment; filename=%s' % filename)
【解决方案2】:

这是我从我们所做的工作应用程序中截取的一个示例。它会创建一个带有 Excel 附件的 HTML 电子邮件。

  import smtplib,email,email.encoders,email.mime.text,email.mime.base

  smtpserver = 'localhost'
  to = ['email@somewhere.com']
  fromAddr = 'automated@hi.com'
  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()

【讨论】:

  • 多部分子类型应该是“混合”而不是“替代”,否则在某些电子邮件客户端中您将看不到附件。
【解决方案3】:

您要检查的是email 模块。它允许您构建符合MIME 的消息,然后使用 smtplib 发送这些消息。

【讨论】:

    【解决方案4】:

    嗯,附件没有以任何特殊方式处理,它们只是消息对象树的“只是”叶子。您可以在email python 包的文档的this 部分找到有关符合 MIME 的消息的任何问题的答案。

    一般来说,任何类型的附件(阅读:原始二进制数据)都可以使用base64来表示 (或类似)Content-Transfer-Encoding.

    【讨论】:

      【解决方案5】:

      以下是发送带有 zip 文件附件和 utf-8 编码主题+正文的电子邮件的方法。

      由于缺乏针对此特定案例的文档和示例,因此很难弄清楚这一点。

      回复中的非 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=["somebody@somewhere.xyz"],
               subject="Test subject æøå",
               body="Test body æøå",
               zipfiles=[],
               server="smtp.somewhere.xyz",
               username="bob",
               password="password123",
               sender="Bob <bob@somewhere.xyz>",
               replyto="=?ISO-8859-1?Q?M=F8=F8=F8?= <bob@somewhere.xyz>"): #: 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 = 'your@mail.com'
        PASS = 'yourpass'
        FROM = 'your@mail.com'
        
        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()
        

        【讨论】:

          猜你喜欢
          • 2016-06-12
          • 1970-01-01
          • 2019-05-29
          • 2012-05-24
          • 1970-01-01
          • 1970-01-01
          • 2011-03-18
          • 1970-01-01
          • 2017-06-16
          相关资源
          最近更新 更多