From 97fd5b49d7738b1122c76b095052d65d7871b6dd Mon Sep 17 00:00:00 2001 From: gressho Date: Fri, 10 Nov 2023 14:06:27 +0100 Subject: [PATCH] Add the possibility to send base64 encoded attachments to invenio-mail. --- invenio_mail/tasks.py | 50 +++++++++++++++++++++++++++++++- tests/test_invenio_mail_tasks.py | 36 +++++++++++++++++++---- 2 files changed, 80 insertions(+), 6 deletions(-) diff --git a/invenio_mail/tasks.py b/invenio_mail/tasks.py index 2eb843b..f038c87 100644 --- a/invenio_mail/tasks.py +++ b/invenio_mail/tasks.py @@ -2,6 +2,7 @@ # # This file is part of Invenio. # Copyright (C) 2015-2018 CERN. +# Copyright (C) 2023 University of Münster. # # Invenio is free software; you can redistribute it and/or modify it # under the terms of the MIT License; see LICENSE file for more details. @@ -10,6 +11,8 @@ from __future__ import absolute_import, print_function +from base64 import b64decode + from celery import shared_task from flask import current_app from flask_mail import Message @@ -27,7 +30,52 @@ def send_email(data): `custom serializer `__ can be created if attachments are really needed. + + This version adds attachments by putting them into a base64 encoded string. + This is not an optimal solution, it might get problematic if they are too + large to handle by the messaging queue, so check for a maximum size beforehand. """ msg = Message() - msg.__dict__.update(data) + msg.subject = data.get("subject") + if "html" in data: + msg.html = data.get("html") + + msg.body = data.get("body") + msg.recipients = data.get("recipients") + msg.sender = data.get("sender") + if "reply_to" in data: + msg.reply_to = data.get("reply_to") + + if "date" in data: + msg.date = data.get("date") + + if "cc" in data: + msg.cc = data.get("cc") + + if "bcc" in data: + msg.cc = data.get("bcc") + + if "charset" in data: + msg.cc = data.get("charset") + + if "extra_headers" in data: + msg.cc = data.get("extra_headers") + + if "mail_options" in data: + msg.cc = data.get("mail_options") + + if "rcpt_options" in data: + msg.cc = data.get("rcpt_options") + + if "attachments" in data: + for attachment in data.get("attachments"): + rawdata = b64decode(attachment.get("base64")) + content_type = "application/octet-stream" + if "content_type" in attachment: + content_type = attachment.get("content_type") + disposition = None + if "disposition" in attachment: + disposition = attachment.get("disposition") + msg.attach(content_type=content_type, data=rawdata, disposition=disposition) + current_app.extensions["mail"].send(msg) diff --git a/tests/test_invenio_mail_tasks.py b/tests/test_invenio_mail_tasks.py index afdade6..f47f452 100644 --- a/tests/test_invenio_mail_tasks.py +++ b/tests/test_invenio_mail_tasks.py @@ -2,6 +2,7 @@ # # This file is part of Invenio. # Copyright (C) 2015-2018 CERN. +# Copyright (C) 2023 University of Münster. # # Invenio is free software; you can redistribute it and/or modify it # under the terms of the MIT License; see LICENSE file for more details. @@ -11,11 +12,6 @@ from __future__ import absolute_import, print_function -import os - -import pkg_resources -from flask_mail import Attachment - from invenio_mail.tasks import send_email @@ -70,3 +66,33 @@ def test_send_message_with_date(email_task_app): result_stream = email_task_app.extensions["invenio-mail"].stream assert result_stream.getvalue().find("Date: Tue, 23 Feb 2016") != -1 + + +def test_send_message_stream_with_attachment(email_task_app): + """Test sending a message with attachment using Task module.""" + with email_task_app.app_context(): + with email_task_app.extensions["mail"].record_messages() as outbox: + msg = { + "subject": "Test2", + "sender": "test2@test2.test2", + "recipients": ["test2@test2.test2"], + "attachments": [ + { + "base64": "RWluIGVpbmZhY2hlciBTdHJpbmcK", + "disposition": "filename.bin", + } + ], + } + + send_email.delay(msg) + + result_stream = email_task_app.extensions["invenio-mail"].stream + assert ( + result_stream.getvalue().find("Content-Type: application/octet-stream") + != -1 + ) + assert ( + result_stream.getvalue().find("Content-Disposition: filename.bin;") + != -1 + ) + assert result_stream.getvalue().find("RWluIGVpbmZhY2hlciBTdHJpbmcK") != -1