使用 MIMEApplication 将 s3 文件附加到 smtplib lib 电子邮件

Posted

技术标签:

【中文标题】使用 MIMEApplication 将 s3 文件附加到 smtplib lib 电子邮件【英文标题】:Attaching an s3 file to an smtplib lib email using MIMEApplication 【发布时间】:2016-08-25 18:22:11 【问题描述】:

我有一个 django 应用程序,它想使用 smtplib 和 email.mime 库将文件从 S3 存储桶附加到电子邮件。

import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication

# This takes the files and attaches each one within the bucket to the email. The server keeps erroring on the "with open(path,'rb') as fil" .

def attach_files(path_to_aws_bucket,msg,files=[]):

    for f in files or []:
        path = path_to_aws_bucket + f
        with open(path,'rb') as fil:
            msg.attach(MIMEApplication(
                fil.read(),
                Content_Disposition='attachment; filename=""' .format(os.path.basename(f)),
                Name=os.path.basename(f)
            ))

    return msg

def build_message(toaddress,fromaddress,subject,body):

    msg = MIMEMultipart('alternative')
    msg['To'] = toaddress
    msg['From'] = fromaddress
    msg['Subject'] = subject
    b = u"" .format(body)
    content = MIMEText(b.encode('utf-8') ,'html','UTF-8')

    msg.attach(content)

    return msg


def send_gmail(msg,username,password,fromaddress,toaddress):

    server = smtplib.SMTP('smtp.gmail.com:587')
    server.ehlo()
    server.starttls()
    server.login(username,password)
    server.sendmail(fromaddress, toaddress , msg.as_string())
    server.quit()

Python 无法打开该文件,因为它声称我给它的任何 s3 url 都不是有效目录。我所有的权限都是正确的。我尝试使用 urllib.opener 打开文件并附加它,但它也引发了错误。

不知道从哪里开始,想知道以前是否有人这样做过。谢谢!

【问题讨论】:

您是如何在 django/python 环境中连接到 s3 的?您是否将本地目录映射到 s3 存储桶? python open 函数期望读取本地文件系统,而不是 s3。 【参考方案1】:

您是否考虑过使用 S3 get_object 代替 smtplib?

from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication
import boto3

msg = MIMEMultipart()
new_body = "asdf"
text_part = MIMEText(new_body, _subtype="html")
msg.attach(text_part)

filename='abc.pdf'
msg["To"] = "amal@gmail.com"
msg["From"] = "amal@gmail.com"
s3_object = boto3.client('s3', 'us-west-2')
s3_object = s3_object.get_object(Bucket=‘bucket-name’, Key=filename)
body = s3_object['Body'].read()

part = MIMEApplication(body, filename)
part.add_header("Content-Disposition", 'attachment', filename=filename)
msg.attach(part)
ses_aws_client = boto3.client('ses', 'us-west-2')
ses_aws_client.send_raw_email(RawMessage="Data" : msg.as_bytes())

【讨论】:

【参考方案2】:

使用 urllib 对我有用,看下面,我有这个 Lambda 函数可以用 smtplib 发送电子邮件:

import smtplib
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.header import Header
from email.utils import formataddr
import urllib
# ['subject','from', 'from_name','to','cc','body','smtp_server','smtp_user','smtp_password']

def lambda_handler(event, context):
    msg = MIMEMultipart('alternative')
    msg['Subject'] = event['subject']
    msg['From'] = formataddr((str(Header(event['from_name'], 'utf-8')), event['from']))
    msg['To'] = event['to']
    msg['Cc'] = event['cc'] # this is comma separated field 

    # Create the body of the message (a plain-text and an HTML version).
    text = "Look in a browser or on a mobile device this HTML msg"
    html = event['body']

    # Record the MIME types of both parts - text/plain and text/html.
    part1 = MIMEText(text, 'plain')
    part2 = MIMEText(html, 'html')

    # Attach parts into message container.
    # According to RFC 2046, the last part of a multipart message, in this case
    # the HTML message, is best and preferred.
    msg.attach(part1)
    msg.attach(part2)

    # Attach files from S3
    opener = urllib.URLopener()
    myurl = "https://s3.amazonaws.com/bucket_name/file_name.pdf"
    fp = opener.open(myurl)

    filename = 'file_name.pdf'
    att = MIMEApplication(fp.read(),_subtype="pdf")
    fp.close()
    att.add_header('Content-Disposition','attachment',filename=filename)
    msg.attach(att)

    # Create de SMTP Object to Send
    s = smtplib.SMTP(event['smtp_server'], 587)
    s.login(event['smtp_user'], event['smtp_password'])
    s.sendmail(msg['From'], [msg['To']], msg.as_string())

    return True

【讨论】:

以上是关于使用 MIMEApplication 将 s3 文件附加到 smtplib lib 电子邮件的主要内容,如果未能解决你的问题,请参考以下文章

S3 中每个目录的最大文件数

将多个文件上传到 Terraform 中的多个 S3 存储桶

将数据从 AWS S3 复制到 Aurora Postgres

增量加载 s3 文件夹文件

将 base64 字符串保存到 Amazon S3

Blueimp 文件上传 - 直接多次上传到 S3