Improved error handling for email support (#4862)

* Improved error handling for email support

- Prevent email sending if email not configured
- Check for tx email address before sending

(cherry picked from commit de541f811ede030ea5eb3136132731e1dafccc31)

* Update InvenTree/email.py

Co-authored-by: Matthias Mair <code@mjmair.com>

* Update InvenTree/email.py

Co-authored-by: Matthias Mair <code@mjmair.com>

* Fix location of file email.py

* Allow dummy emails in testing

* Provide default email in testing mode

* Fix to get test working

---------

Co-authored-by: Matthias Mair <code@mjmair.com>
This commit is contained in:
Oliver 2023-05-24 07:33:31 +10:00 committed by GitHub
parent 96b7845d84
commit 91d79dc3ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 90 additions and 59 deletions

View File

@ -2,6 +2,7 @@
"""Provides extra global data to all templates."""
import InvenTree.email
import InvenTree.status
from InvenTree.status_codes import (BuildStatus, PurchaseOrderStatus,
ReturnOrderLineStatus, ReturnOrderStatus,
@ -28,7 +29,7 @@ def health_status(request):
status = {
'django_q_running': InvenTree.status.is_worker_running(),
'email_configured': InvenTree.status.is_email_configured(),
'email_configured': InvenTree.email.is_email_configured(),
}
# The following keys are required to denote system health

View File

@ -0,0 +1,82 @@
"""Code for managing email functionality in InvenTree."""
import logging
from django.conf import settings
from django.core import mail as django_mail
import InvenTree.ready
import InvenTree.tasks
logger = logging.getLogger('inventree')
def is_email_configured():
"""Check if email backend is configured.
NOTE: This does not check if the configuration is valid!
"""
configured = True
if InvenTree.ready.isInTestMode():
return False
if InvenTree.ready.isImportingData():
return False
if not settings.EMAIL_HOST:
configured = False
# Display warning unless in test mode
if not settings.TESTING: # pragma: no cover
logger.debug("EMAIL_HOST is not configured")
# Display warning unless in test mode
if not settings.EMAIL_HOST_USER and not settings.TESTING: # pragma: no cover
logger.debug("EMAIL_HOST_USER is not configured")
# Display warning unless in test mode
if not settings.EMAIL_HOST_PASSWORD and not settings.TESTING: # pragma: no cover
logger.debug("EMAIL_HOST_PASSWORD is not configured")
return configured
def send_email(subject, body, recipients, from_email=None, html_message=None):
"""Send an email with the specified subject and body, to the specified recipients list."""
if type(recipients) == str:
recipients = [recipients]
import InvenTree.ready
import InvenTree.status
if InvenTree.ready.isImportingData():
# If we are importing data, don't send emails
return
if not InvenTree.email.is_email_configured() and not settings.TESTING:
# Email is not configured / enabled
return
# If a *from_email* is not specified, ensure that the default is set
if not from_email:
from_email = settings.DEFAULT_FROM_EMAIL
# If we still don't have a valid from_email, then we can't send emails
if not from_email:
if settings.TESTING:
from_email = 'from@test.com'
else:
logger.error("send_email failed: DEFAULT_FROM_EMAIL not specified")
return
InvenTree.tasks.offload_task(
django_mail.send_mail,
subject,
body,
from_email,
recipients,
fail_silently=False,
html_message=html_message
)

View File

@ -4,13 +4,13 @@
import logging
from datetime import timedelta
from django.conf import settings
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from django_q.models import Success
from django_q.monitor import Stat
import InvenTree.email
import InvenTree.ready
logger = logging.getLogger("inventree")
@ -41,37 +41,6 @@ def is_worker_running(**kwargs):
return results.exists()
def is_email_configured():
"""Check if email backend is configured.
NOTE: This does not check if the configuration is valid!
"""
configured = True
if InvenTree.ready.isInTestMode():
return False
if InvenTree.ready.isImportingData():
return False
if not settings.EMAIL_HOST:
configured = False
# Display warning unless in test mode
if not settings.TESTING: # pragma: no cover
logger.debug("EMAIL_HOST is not configured")
# Display warning unless in test mode
if not settings.TESTING: # pragma: no cover
logger.debug("EMAIL_HOST_USER is not configured")
# Display warning unless in test mode
if not settings.TESTING: # pragma: no cover
logger.debug("EMAIL_HOST_PASSWORD is not configured")
return configured
def check_system_health(**kwargs):
"""Check that the InvenTree system is running OK.
@ -91,7 +60,7 @@ def check_system_health(**kwargs):
result = False
logger.warning(_("Background worker check failed"))
if not is_email_configured(): # pragma: no cover
if not InvenTree.email.is_email_configured(): # pragma: no cover
result = False
logger.warning(_("Email backend not configured"))

View File

@ -12,7 +12,6 @@ from datetime import datetime, timedelta
from typing import Callable, List
from django.conf import settings
from django.core import mail as django_mail
from django.core.exceptions import AppRegistryNotReady
from django.core.management import call_command
from django.db import DEFAULT_DB_ALIAS, connections
@ -559,28 +558,6 @@ def run_backup():
record_task_success('run_backup')
def send_email(subject, body, recipients, from_email=None, html_message=None):
"""Send an email with the specified subject and body, to the specified recipients list."""
if type(recipients) == str:
recipients = [recipients]
import InvenTree.ready
if InvenTree.ready.isImportingData():
# If we are importing data, don't send emails
return
offload_task(
django_mail.send_mail,
subject,
body,
from_email,
recipients,
fail_silently=False,
html_message=html_message
)
@scheduled_task(ScheduledTask.DAILY)
def check_for_migrations(worker: bool = True):
"""Checks if migrations are needed.

View File

@ -12,6 +12,7 @@ from allauth.account.models import EmailAddress
from plugin.events import trigger_event
import common.notifications
import build.models
import InvenTree.email
import InvenTree.helpers
import InvenTree.tasks
from InvenTree.status_codes import BuildStatus
@ -101,7 +102,7 @@ def check_build_stock(build: build.models.Build):
recipients = emails.values_list('email', flat=True)
InvenTree.tasks.send_email(subject, '', recipients, html_message=html_message)
InvenTree.email.send_email(subject, '', recipients, html_message=html_message)
def notify_overdue_build_order(bo: build.models.Build):

View File

@ -7,6 +7,7 @@ import requests
from allauth.account.models import EmailAddress
import common.models
import InvenTree.email
import InvenTree.helpers
import InvenTree.tasks
from plugin import InvenTreePlugin, registry
@ -115,7 +116,7 @@ class InvenTreeCoreNotificationsPlugin(SettingsContentMixin, SettingsMixin, Inve
if instance_title:
subject = f'[{instance_title}] {subject}'
InvenTree.tasks.send_email(subject, '', targets, html_message=html_message)
InvenTree.email.send_email(subject, '', targets, html_message=html_message)
return True