mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-04-02 13:45:10 -05:00
Fix: use MIMEBase for email attachments (#8762)
This commit is contained in:
parent
283bcb4c91
commit
a32077566b
61
src/documents/mail.py
Normal file
61
src/documents/mail.py
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
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()
|
@ -12,7 +12,6 @@ from celery.signals import task_postrun
|
|||||||
from celery.signals import task_prerun
|
from celery.signals import task_prerun
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.core.mail import EmailMessage
|
|
||||||
from django.db import DatabaseError
|
from django.db import DatabaseError
|
||||||
from django.db import close_old_connections
|
from django.db import close_old_connections
|
||||||
from django.db import models
|
from django.db import models
|
||||||
@ -30,6 +29,7 @@ from documents.data_models import DocumentMetadataOverrides
|
|||||||
from documents.file_handling import create_source_path_directory
|
from documents.file_handling import create_source_path_directory
|
||||||
from documents.file_handling import delete_empty_directories
|
from documents.file_handling import delete_empty_directories
|
||||||
from documents.file_handling import generate_unique_filename
|
from documents.file_handling import generate_unique_filename
|
||||||
|
from documents.mail import send_email
|
||||||
from documents.models import Correspondent
|
from documents.models import Correspondent
|
||||||
from documents.models import CustomField
|
from documents.models import CustomField
|
||||||
from documents.models import CustomFieldInstance
|
from documents.models import CustomFieldInstance
|
||||||
@ -972,17 +972,13 @@ def run_workflows(
|
|||||||
doc_url,
|
doc_url,
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
email = EmailMessage(
|
n_messages = send_email(
|
||||||
subject=subject,
|
subject=subject,
|
||||||
body=body,
|
body=body,
|
||||||
to=action.email.to.split(","),
|
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(
|
logger.debug(
|
||||||
f"Sent {n_messages} notification email(s) to {action.email.to}",
|
f"Sent {n_messages} notification email(s) to {action.email.to}",
|
||||||
extra={"group": logging_group},
|
extra={"group": logging_group},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user