forked from ScoDoc/ScoDoc
133 lines
4.0 KiB
Python
133 lines
4.0 KiB
Python
# -*- coding: UTF-8 -*
|
|
##############################################################################
|
|
# ScoDoc
|
|
# Copyright (c) 1999 - 2024 Emmanuel Viennet. All rights reserved.
|
|
# See LICENSE
|
|
##############################################################################
|
|
|
|
import datetime
|
|
from threading import Thread
|
|
|
|
from flask import current_app, g
|
|
from flask_mail import BadHeaderError, Message
|
|
|
|
from app import log, mail
|
|
from app.models.departements import Departement
|
|
from app.models.config import ScoDocSiteConfig
|
|
from app.scodoc import sco_preferences
|
|
|
|
|
|
def send_async_email(app, msg):
|
|
"Send an email, async"
|
|
with app.app_context():
|
|
try:
|
|
mail.send(msg)
|
|
except BadHeaderError:
|
|
log(
|
|
f"""send_async_email: BadHeaderError
|
|
msg={msg}
|
|
"""
|
|
)
|
|
raise
|
|
|
|
|
|
def send_email(
|
|
subject: str,
|
|
sender: str,
|
|
recipients: list,
|
|
text_body: str,
|
|
html_body: str | None = None,
|
|
bcc=(),
|
|
attachments=(),
|
|
):
|
|
"""
|
|
Send an email. _All_ ScoDoc mails SHOULD be sent using this function.
|
|
|
|
If html_body is specified, build a multipart message with HTML content,
|
|
else send a plain text email.
|
|
|
|
attachements: list of dict { 'filename', 'mimetype', 'data' }
|
|
"""
|
|
msg = Message(subject, sender=sender, recipients=recipients, bcc=bcc)
|
|
msg.body = text_body
|
|
msg.html = html_body
|
|
if attachments:
|
|
for attachment in attachments:
|
|
msg.attach(
|
|
attachment["filename"], attachment["mimetype"], attachment["data"]
|
|
)
|
|
send_message(msg)
|
|
|
|
|
|
def send_message(msg: Message):
|
|
"""Send a message.
|
|
All ScoDoc emails MUST be sent by this function.
|
|
|
|
In mail debug mode, addresses are discarded and all mails are sent to the
|
|
specified debugging address.
|
|
"""
|
|
email_test_mode_address = False
|
|
if hasattr(g, "scodoc_dept"):
|
|
# on est dans un département, on peut accéder aux préférences
|
|
email_test_mode_address = sco_preferences.get_preference(
|
|
"email_test_mode_address"
|
|
)
|
|
if email_test_mode_address:
|
|
# Mode spécial test: remplace les adresses de destination
|
|
orig_to = msg.recipients
|
|
orig_cc = msg.cc
|
|
orig_bcc = msg.bcc
|
|
msg.recipients = [email_test_mode_address]
|
|
msg.cc = None
|
|
msg.bcc = None
|
|
msg.subject = "[TEST SCODOC] " + msg.subject
|
|
msg.body = (
|
|
f"""--- Message ScoDoc dérouté pour tests ---
|
|
Adresses d'origine:
|
|
to : {orig_to}
|
|
cc : {orig_cc}
|
|
bcc: {orig_bcc}
|
|
---
|
|
\n\n"""
|
|
+ msg.body
|
|
)
|
|
now = datetime.datetime.now()
|
|
formatted_time = now.strftime("%Y-%m-%d %H:%M:%S") + ".{:03d}".format(
|
|
now.microsecond // 1000
|
|
)
|
|
current_app.logger.info(
|
|
f"""[{formatted_time}] email sent to{
|
|
' (mode test)' if email_test_mode_address else ''
|
|
}: {msg.recipients}
|
|
from sender {msg.sender}
|
|
"""
|
|
)
|
|
Thread(
|
|
target=send_async_email, args=(current_app._get_current_object(), msg)
|
|
).start()
|
|
|
|
|
|
def get_from_addr(dept_acronym: str = None):
|
|
"""L'adresse "from" à utiliser pour envoyer un mail
|
|
|
|
Si le departement est spécifié, ou si l'attribut `g.scodoc_dept`existe,
|
|
prend le `email_from_addr` des préférences de ce département si ce champ
|
|
est non vide.
|
|
Sinon, utilise le paramètre global `email_from_addr`.
|
|
Sinon, la variable de config `SCODOC_MAIL_FROM`.
|
|
"""
|
|
dept_acronym = dept_acronym or getattr(g, "scodoc_dept", None)
|
|
if dept_acronym:
|
|
dept = Departement.query.filter_by(acronym=dept_acronym).first()
|
|
if dept:
|
|
from_addr = (
|
|
sco_preferences.get_preference("email_from_addr", dept_id=dept.id) or ""
|
|
).strip()
|
|
if from_addr:
|
|
return from_addr
|
|
return (
|
|
ScoDocSiteConfig.get("email_from_addr")
|
|
or current_app.config["SCODOC_MAIL_FROM"]
|
|
or "none"
|
|
)
|