diff --git a/InvenTree/InvenTree/context.py b/InvenTree/InvenTree/context.py index f6cb54af7f..3803895010 100644 --- a/InvenTree/InvenTree/context.py +++ b/InvenTree/InvenTree/context.py @@ -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 diff --git a/InvenTree/InvenTree/email.py b/InvenTree/InvenTree/email.py new file mode 100644 index 0000000000..20d78a498d --- /dev/null +++ b/InvenTree/InvenTree/email.py @@ -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 + ) diff --git a/InvenTree/InvenTree/status.py b/InvenTree/InvenTree/status.py index 46fa09b7b7..cb837a2439 100644 --- a/InvenTree/InvenTree/status.py +++ b/InvenTree/InvenTree/status.py @@ -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")) diff --git a/InvenTree/InvenTree/tasks.py b/InvenTree/InvenTree/tasks.py index bfa5a6a38c..0d4ba52861 100644 --- a/InvenTree/InvenTree/tasks.py +++ b/InvenTree/InvenTree/tasks.py @@ -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. diff --git a/InvenTree/build/tasks.py b/InvenTree/build/tasks.py index 6623686155..0acf05d5da 100644 --- a/InvenTree/build/tasks.py +++ b/InvenTree/build/tasks.py @@ -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): diff --git a/InvenTree/plugin/builtin/integration/core_notifications.py b/InvenTree/plugin/builtin/integration/core_notifications.py index c178e8960e..d789927515 100644 --- a/InvenTree/plugin/builtin/integration/core_notifications.py +++ b/InvenTree/plugin/builtin/integration/core_notifications.py @@ -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