如何在Django中将S3文件附加到电子邮件

5

我正在尝试在电子邮件中附加保存在S3存储桶中的媒体文件,使用以下代码行:

email.attach_file(standard.download.url)

该模型定义如下:

class Standard(models.Model):
    name = models.CharField(max_length = 51)
    download = models.FileField(upload_to="standard_downloads/", null=True, blank=True)

    def __str__(self):
        return self.name

settings.py 文件中,我定义了我的媒体文件如下:

AWS_DEFAULT_ACL = 'public-read'
AWS_S3_CUSTOM_DOMAIN = '%s.s3.amazonaws.com' % AWS_STORAGE_BUCKET_NAME
AWS_S3_OBJECT_PARAMETERS = {
    'CacheControl': 'max-age=86400',
}
DEFAULT_FILE_STORAGE = 'sme.storage_backends.MediaStorage'
MEDIA_ROOT = 'https://%s.s3.amazonaws.com/media/' % AWS_STORAGE_BUCKET_NAME

运行代码时出现以下错误:

没有此文件或目录: 'https:/bucket-name.s3.amazonaws.com/media/standard_downloads/filename.ext'

请注意,它显示为 https:/ (只有一个 /)。我应该如何进行更正?


这是发生在你的本地主机还是像 NGINX 或 Apache 之类的服务器上吗? - bhaskarc
我正在通过ElasticBeanStalk在EC2实例上运行它。 - HenryM
2个回答

7

以下是从Django中的attach_file函数的源代码中获取的信息,它明确表示-仅限于从文件系统附加文件。 它不适用于远程URL。 当您提供一个URL时,它会认为您正在引用本地文件,因此会将所有双斜杠转义为单斜杠。

def attach_file(self, path, mimetype=None):
    """
    Attach a file from the filesystem.

    Set the mimetype to DEFAULT_ATTACHMENT_MIME_TYPE if it isn't specified
    and cannot be guessed.

    For a text/* mimetype (guessed or specified), decode the file's content
    as UTF-8. If that fails, set the mimetype to
    DEFAULT_ATTACHMENT_MIME_TYPE and don't decode the content.
    """
    path = Path(path)
    with path.open('rb') as file:
        content = file.read()
        self.attach(path.name, content, mimetype)

Django没有提供这方面的内置功能。您需要编写自定义代码,也可以使用像requestboto这样的库。基本上的思路是从远程URL获取,保存为temp文件,然后在此文件上使用attach。以下是如何在fly上获取文件的示例:
from django.core.mail.message import attach
import requests
response = requests.get("http://yoururl/somefile.pdf")
email.attach('My file',response.read(),mimetype="application/pdf")

如果我正在使用S3存储桶,那么如何附加文件? - HenryM
我不知道文件的MIME类型,所以我使用了response = requests.get(standard.download.url)email.attach(standard.download.name, response.read())。但现在出现了错误'Response' object has no attribute 'read' - HenryM
2
将“response.read()”更改为“response.content”,它就可以工作了。谢谢。 - HenryM
或者 email.attach(os.path.basename(standard.download.file.name), standard.download.file.read(), "application/pdf") 将自动为您检索文件。 - DrMeers

1
更好的方法是利用default_storage,它可以适用于本地文件存储、S3或任何其他存储后端。
from django.core.files.storage import default_storage

msg = EmailMessage(
    subject="Your subject",
    body="Your Message",
    from_email="email@yourdomain.com",
    to=["email@anotherdomain.com"],
)
    
filename = "standard_downloads/filename.ext"
with default_storage.open(filename, "r") as fh:
    msg.attach(filename, fh.read())

msg.send()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接