How do I send attachments using SMTP?

后端 未结 6 890
爱一瞬间的悲伤
爱一瞬间的悲伤 2020-12-01 01:55

I want to write a program that sends email using Python\'s smtplib. I searched through the document and the RFCs, but couldn\'t find anything related to attachments. Thus,

相关标签:
6条回答
  • 2020-12-01 02:04

    What you want to check out is the email module. It lets you build MIME-compliant messages that you then send with smtplib.

    0 讨论(0)
  • 2020-12-01 02:04

    Here's an example I snipped out of a work application we did. It creates an HTML email with an Excel attachment.

      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()
    
    0 讨论(0)
  • 2020-12-01 02:05

    Here's how to send e-mails with zip file attachments and utf-8 encoded subject+body.

    It was not straightforward to figure this one out, due to lack of documentation and samples for this particular case.

    Non-ascii characters in replyto needs to be encoded with, for instance, ISO-8859-1. There probably exists a function that can do this.

    Tip:
    Send yourself an e-mail, save it and examine the content to figure out how to do the same thing in Python.

    Here's the code, for 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()
    
    0 讨论(0)
  • 2020-12-01 02:14

    Well, attachments are not treated in any special ways, they are "just" leaves of the Message-object tree. You can find the answers to any questions regarding MIME-compliant mesasges in this section of the documentation on the email python package.

    In general, any kind of attachment (read: raw binary data) can be represented by using base64 (or similar) Content-Transfer-Encoding.

    0 讨论(0)
  • 2020-12-01 02:22

    Here is an example of a message with a PDF attachment, a text "body" and sending via 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()
    
    0 讨论(0)
  • 2020-12-01 02:24
    # -*- 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()
    
    0 讨论(0)
提交回复
热议问题