mirror of https://github.com/jumpserver/jumpserver
perf: 邮箱支持exchange协议
parent
2a29cd0e70
commit
9ede3670a7
|
@ -2,7 +2,7 @@ import os
|
|||
|
||||
from celery import shared_task
|
||||
from django.conf import settings
|
||||
from django.core.mail import send_mail, EmailMultiAlternatives
|
||||
from django.core.mail import send_mail, EmailMultiAlternatives, get_connection
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
import jms_storage
|
||||
|
||||
|
@ -11,6 +11,16 @@ from .utils import get_logger
|
|||
logger = get_logger(__file__)
|
||||
|
||||
|
||||
def get_email_connection(**kwargs):
|
||||
email_backend_map = {
|
||||
'smtp': 'django.core.mail.backends.smtp.EmailBackend',
|
||||
'exchange': 'jumpserver.rewriting.exchange.EmailBackend'
|
||||
}
|
||||
return get_connection(
|
||||
backend=email_backend_map.get(settings.EMAIL_PROTOCOL), **kwargs
|
||||
)
|
||||
|
||||
|
||||
def task_activity_callback(self, subject, message, recipient_list, *args, **kwargs):
|
||||
from users.models import User
|
||||
email_list = recipient_list
|
||||
|
@ -40,7 +50,7 @@ def send_mail_async(*args, **kwargs):
|
|||
|
||||
args = tuple(args)
|
||||
try:
|
||||
return send_mail(*args, **kwargs)
|
||||
return send_mail(connection=get_email_connection(), *args, **kwargs)
|
||||
except Exception as e:
|
||||
logger.error("Sending mail error: {}".format(e))
|
||||
|
||||
|
@ -55,7 +65,8 @@ def send_mail_attachment_async(subject, message, recipient_list, attachment_list
|
|||
subject=subject,
|
||||
body=message,
|
||||
from_email=from_email,
|
||||
to=recipient_list
|
||||
to=recipient_list,
|
||||
connection=get_email_connection(),
|
||||
)
|
||||
for attachment in attachment_list:
|
||||
email.attach_file(attachment)
|
||||
|
|
|
@ -453,6 +453,7 @@ class Config(dict):
|
|||
'CUSTOM_SMS_REQUEST_METHOD': 'get',
|
||||
|
||||
# Email
|
||||
'EMAIL_PROTOCOL': 'smtp',
|
||||
'EMAIL_CUSTOM_USER_CREATED_SUBJECT': _('Create account successfully'),
|
||||
'EMAIL_CUSTOM_USER_CREATED_HONORIFIC': _('Hello'),
|
||||
'EMAIL_CUSTOM_USER_CREATED_BODY': _('Your account has been created successfully'),
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
import urllib3
|
||||
|
||||
from urllib3.exceptions import InsecureRequestWarning
|
||||
|
||||
from django.core.mail.backends.base import BaseEmailBackend
|
||||
from django.core.mail.message import sanitize_address
|
||||
from django.conf import settings
|
||||
from exchangelib import Account, Credentials, Configuration, DELEGATE
|
||||
from exchangelib import Mailbox, Message, HTMLBody, FileAttachment
|
||||
from exchangelib import BaseProtocol, NoVerifyHTTPAdapter
|
||||
from exchangelib.errors import TransportError
|
||||
|
||||
|
||||
urllib3.disable_warnings(InsecureRequestWarning)
|
||||
BaseProtocol.HTTP_ADAPTER_CLS = NoVerifyHTTPAdapter
|
||||
|
||||
|
||||
class EmailBackend(BaseEmailBackend):
|
||||
def __init__(
|
||||
self,
|
||||
service_endpoint=None,
|
||||
username=None,
|
||||
password=None,
|
||||
fail_silently=False,
|
||||
**kwargs,
|
||||
):
|
||||
super().__init__(fail_silently=fail_silently)
|
||||
self.service_endpoint = service_endpoint or settings.EMAIL_HOST
|
||||
self.username = settings.EMAIL_HOST_USER if username is None else username
|
||||
self.password = settings.EMAIL_HOST_PASSWORD if password is None else password
|
||||
self._connection = None
|
||||
|
||||
def open(self):
|
||||
if self._connection:
|
||||
return False
|
||||
|
||||
try:
|
||||
config = Configuration(
|
||||
service_endpoint=self.service_endpoint, credentials=Credentials(
|
||||
username=self.username, password=self.password
|
||||
)
|
||||
)
|
||||
self._connection = Account(self.username, config=config, access_type=DELEGATE)
|
||||
return True
|
||||
except TransportError:
|
||||
if not self.fail_silently:
|
||||
raise
|
||||
|
||||
def close(self):
|
||||
self._connection = None
|
||||
|
||||
def send_messages(self, email_messages):
|
||||
if not email_messages:
|
||||
return 0
|
||||
|
||||
new_conn_created = self.open()
|
||||
if not self._connection or new_conn_created is None:
|
||||
return 0
|
||||
num_sent = 0
|
||||
for message in email_messages:
|
||||
sent = self._send(message)
|
||||
if sent:
|
||||
num_sent += 1
|
||||
if new_conn_created:
|
||||
self.close()
|
||||
return num_sent
|
||||
|
||||
def _send(self, email_message):
|
||||
if not email_message.recipients():
|
||||
return False
|
||||
|
||||
encoding = settings.DEFAULT_CHARSET
|
||||
from_email = sanitize_address(email_message.from_email, encoding)
|
||||
recipients = [
|
||||
Mailbox(email_address=sanitize_address(addr, encoding)) for addr in email_message.recipients()
|
||||
]
|
||||
try:
|
||||
message_body = email_message.body
|
||||
alternatives = email_message.alternatives or []
|
||||
attachments = []
|
||||
for attachment in email_message.attachments or []:
|
||||
name, content, mimetype = attachment
|
||||
if isinstance(content, str):
|
||||
content = content.encode(encoding)
|
||||
attachments.append(
|
||||
FileAttachment(name=name, content=content, content_type=mimetype)
|
||||
)
|
||||
for alternative in alternatives:
|
||||
if alternative[1] == 'text/html':
|
||||
message_body = HTMLBody(alternative[0])
|
||||
break
|
||||
|
||||
email_message = Message(
|
||||
account=self._connection, subject=email_message.subject,
|
||||
body=message_body, to_recipients=recipients, sender=from_email,
|
||||
attachments=[]
|
||||
)
|
||||
email_message.attach(attachments)
|
||||
email_message.send_and_save()
|
||||
except Exception as error:
|
||||
if not self.fail_silently:
|
||||
raise error
|
||||
return False
|
||||
return True
|
|
@ -331,6 +331,7 @@ if DEBUG_DEV:
|
|||
FIXTURE_DIRS = [os.path.join(BASE_DIR, 'fixtures'), ]
|
||||
|
||||
# Email config
|
||||
EMAIL_PROTOCOL = CONFIG.EMAIL_PROTOCOL
|
||||
EMAIL_HOST = CONFIG.EMAIL_HOST
|
||||
EMAIL_PORT = CONFIG.EMAIL_PORT
|
||||
EMAIL_HOST_USER = CONFIG.EMAIL_HOST_USER
|
||||
|
|
|
@ -4,11 +4,12 @@
|
|||
from smtplib import SMTPSenderRefused
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.mail import send_mail, get_connection
|
||||
from django.core.mail import send_mail
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from rest_framework.views import Response, APIView
|
||||
|
||||
from common.utils import get_logger
|
||||
from common.tasks import get_email_connection as get_connection
|
||||
from .. import serializers
|
||||
|
||||
logger = get_logger(__file__)
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
# coding: utf-8
|
||||
#
|
||||
|
||||
from django.db import models
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from rest_framework import serializers
|
||||
|
||||
from common.serializers.fields import EncryptedField
|
||||
|
||||
|
||||
__all__ = [
|
||||
'MailTestSerializer', 'EmailSettingSerializer',
|
||||
'EmailContentSettingSerializer', 'SMSBackendSerializer',
|
||||
|
@ -18,14 +19,20 @@ class MailTestSerializer(serializers.Serializer):
|
|||
|
||||
|
||||
class EmailSettingSerializer(serializers.Serializer):
|
||||
# encrypt_fields 现在使用 write_only 来判断了
|
||||
PREFIX_TITLE = _('Email')
|
||||
|
||||
EMAIL_HOST = serializers.CharField(max_length=1024, required=True, label=_("SMTP host"))
|
||||
EMAIL_PORT = serializers.CharField(max_length=5, required=True, label=_("SMTP port"))
|
||||
EMAIL_HOST_USER = serializers.CharField(max_length=128, required=True, label=_("SMTP account"))
|
||||
class EmailProtocol(models.TextChoices):
|
||||
smtp = 'smtp', _('SMTP')
|
||||
exchange = 'exchange', _('EXCHANGE')
|
||||
|
||||
EMAIL_PROTOCOL = serializers.ChoiceField(
|
||||
choices=EmailProtocol.choices, label=_("Protocol"), default=EmailProtocol.smtp
|
||||
)
|
||||
EMAIL_HOST = serializers.CharField(max_length=1024, required=True, label=_("Host"))
|
||||
EMAIL_PORT = serializers.CharField(max_length=5, required=True, label=_("Port"))
|
||||
EMAIL_HOST_USER = serializers.CharField(max_length=128, required=True, label=_("Account"))
|
||||
EMAIL_HOST_PASSWORD = EncryptedField(
|
||||
max_length=1024, required=False, label=_("SMTP password"),
|
||||
max_length=1024, required=False, label=_("Password"),
|
||||
help_text=_("Tips: Some provider use token except password")
|
||||
)
|
||||
EMAIL_FROM = serializers.CharField(
|
||||
|
|
Loading…
Reference in New Issue