--- /dev/null
+from email.encoders import encode_base64
+from email.mime.base import MIMEBase
+from pathlib import Path
+from urllib.parse import quote
+
+from django.conf import settings
+from django.core.mail import EmailMessage
+from filelock import FileLock
+
+
+def send_email(
+ subject: str,
+ body: str,
+ to: list[str],
+ attachment: Path | None = None,
+ attachment_mime_type: str | None = None,
+) -> int:
+ """
+ Send an email with an optional attachment.
+ TODO: re-evaluate this pending https://code.djangoproject.com/ticket/35581 / https://github.com/django/django/pull/18966
+ """
+ email = EmailMessage(
+ subject=subject,
+ body=body,
+ to=to,
+ )
+ if attachment:
+ # Something could be renaming the file concurrently so it can't be attached
+ with FileLock(settings.MEDIA_LOCK), attachment.open("rb") as f:
+ file_content = f.read()
+
+ main_type, sub_type = (
+ attachment_mime_type.split("/", 1)
+ if attachment_mime_type
+ else ("application", "octet-stream")
+ )
+ mime_part = MIMEBase(main_type, sub_type)
+ mime_part.set_payload(file_content)
+
+ encode_base64(mime_part)
+
+ # see https://github.com/stumpylog/tika-client/blob/f65a2b792fc3cf15b9b119501bba9bddfac15fcc/src/tika_client/_base.py#L46-L57
+ try:
+ attachment.name.encode("ascii")
+ except UnicodeEncodeError:
+ filename_safed = attachment.name.encode("ascii", "ignore").decode(
+ "ascii",
+ )
+ filepath_quoted = quote(attachment.name, encoding="utf-8")
+ mime_part.add_header(
+ "Content-Disposition",
+ f"attachment; filename={filename_safed}; filename*=UTF-8''{filepath_quoted}",
+ )
+ else:
+ mime_part.add_header(
+ "Content-Disposition",
+ f"attachment; filename={attachment.name}",
+ )
+
+ email.attach(mime_part)
+ return email.send()
from celery.signals import task_prerun
from django.conf import settings
from django.contrib.auth.models import User
-from django.core.mail import EmailMessage
from django.db import DatabaseError
from django.db import close_old_connections
from django.db import models
from documents.file_handling import create_source_path_directory
from documents.file_handling import delete_empty_directories
from documents.file_handling import generate_unique_filename
+from documents.mail import send_email
from documents.models import Correspondent
from documents.models import CustomField
from documents.models import CustomFieldInstance
doc_url,
)
try:
- email = EmailMessage(
+ n_messages = send_email(
subject=subject,
body=body,
to=action.email.to.split(","),
+ attachment=original_file if action.email.include_document else None,
+ attachment_mime_type=document.mime_type,
)
- if action.email.include_document:
- # Something could be renaming the file concurrently so it can't be attached
- with FileLock(settings.MEDIA_LOCK):
- document.refresh_from_db()
- email.attach_file(original_file)
- n_messages = email.send()
logger.debug(
f"Sent {n_messages} notification email(s) to {action.email.to}",
extra={"group": logging_group},