使用 MIMEBase 将 CSV 附加到电子邮件,仅附加 'bin' 个文档

Attach CSV to E-Mail with MIMEBase, only attaches 'bin' document

我想编写一个函数,将 csv 文件附加到带有 HTML 文本的电子邮件。一切正常。我发送带有正文的电子邮件和带有正确信息的附件。只是数据格式不对。我在 MIMEBASE('application', 'octet-stream') 尝试了不同的品种。这个给了我一个 '.bin' 数据,我无法在 macOS 上打开它。其他人给了我一个包含正确数据的纯文本数据,但我不想手动将其复制到 csv 中。有人能解决我如何以 '.csv' 格式获取数据吗?我在这里找到的大多数解决方案看起来就像我下面的代码。

代码:

def send_mail(receiver, subject, filepath, attachname):
    
    #login information
    port = 123
    smtp_server = "test.server.com"
    login = "testlogin" # your login 
    password = "12345678910" # your password 

    # specify the sender’s and receiver’s email addresses and text in HTML
    sender = "testmail@test.com"
    receiver = receiver
    message = MIMEMultipart()
    message["Subject"] = subject
    message["From"] = sender
    message["To"] = COMMASPACE.join([receiver])
    html_text = """\
    <html>
      <body>
        <p>Hi ,<br>
        <p>kind regards</p>
        <p> This is an automatized Mail </p>
      </body>
    </html>
    """
    # convert both parts to MIMEText objects and add them to the MIMEMultipart message
    text = MIMEText(html_text, "html")
    message.attach(text)
    
    #add a file as attachment
    file = open(filepath, "rb")
    att = MIMEBase('application', 'octet-stream')
    att.set_payload(file.read())
    encoders.encode_base64(att)
    att.add_header("Content_Disposition",
                    'attachment', filename = attachname)
    message.attach(att)
    try:
        #send your message with credentials specified above
        with smtplib.SMTP(smtp_server, port) as server:
            server.connect(smtp_server, port)
            server.ehlo()
            server.starttls()
            server.ehlo()
            server.login(login, password)
            server.sendmail(sender, receiver, message.as_string())

        # tell the script to report if your message was sent or which errors need to be fixed 
        print('Sent')
    except (gaierror, ConnectionRefusedError):
        print('Failed to connect to the server. Bad connection settings?')
    except smtplib.SMTPServerDisconnected:
        print('Failed to connect to the server. Wrong user/password?')
    except smtplib.SMTPException as e:
        print('SMTP error occurred: ' + str(e))

send_mail('testmail@test.com', 'TEST', '/Users/Changer/Desktop/test.csv', 'test.csv')

电子邮件客户端可能会使用附件部分的内容类型来确定使用哪个程序打开附件,因此指定合适的内容类型可能会有所帮助。

此代码使用标准库的 mimetypes 模块尝试根据其名称猜测附件的正确内容类型:

import mimetypes

mimetypes.init()

def send_mail(receiver, subject, filepath, attachname):
    ...

    mimetype, _ = mimetypes.guess_type(attachname)
    if mimetype is None:
        mimetype = 'application/octet-stream'
    type_, _, subtype = mimetype.partition('/')
    att = MIMEBase(type_, subtype)
    ...

以上代码将为附件生成这些 headers:

b'Content-Type: text/x-comma-separated-values'
b'MIME-Version: 1.0'
b'Content-Transfer-Encoding: base64'
b'Content_Disposition: attachment; filename="test.csv"'

mac 是否会使用电子表格应用程序打开 csv(我假设这就是您想要的)取决于 machine 的配置(参见 this blog例子)。如果您想确保在电子表格中打开文件,将其转换为电子表格格式并发送电子表格可能更有效。