Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
mail_util.py166 linesDownload Raw Back to flask_security
1"""2    flask_security.mail_util3    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~4 5    Utility class providing methods for validating, normalizing and sending emails.6 7    :copyright: (c) 2020-2024 by J. Christopher Wagner (jwag).8    :license: MIT, see LICENSE for more details.9 10    While this default implementation uses Flask-Mailman - we want to make sure that11    Flask-Mailman isn't REQUIRED (if this implementation isn't used).12"""13 14from __future__ import annotations15 16import typing as t17 18import email_validator19from flask import current_app20 21from .utils import config_value, get_message22 23if t.TYPE_CHECKING:  # pragma: no cover24    import flask25 26 27class EmailValidateException(ValueError):28    """This is raised for any email validation errors.29    This can be used by custom MailUtil implementations to provide30    custom error messages.31    """32 33    def __init__(self, message: str) -> None:34        self.msg = message35 36 37class MailUtil:38    """39    Utility class providing methods for validating, normalizing and sending emails.40 41    This default class uses the email_validator package to handle validation and42    normalization, and the flask_mailman package (if initialized) to send emails.43 44    To provide your own implementation, pass in the class as ``mail_util_cls``45    at init time.  Your class will be instantiated once as part of app initialization.46 47    .. versionadded:: 4.0.048    """49 50    def __init__(self, app: flask.Flask):51        """Instantiate class.52 53        :param app: The Flask application being initialized.54        """55        pass56 57    def send_mail(58        self,59        template: str,60        subject: str,61        recipient: str,62        sender: str | tuple,63        body: str,64        html: str | None,65        **kwargs: t.Any,66    ) -> None:67        """Send an email via the Flask-Mailman or Flask-Mail or other mail extension.68 69        :param template: the Template name. The message has already been rendered70            however this might be useful to differentiate why the email is being sent.71        :param subject: Email subject72        :param recipient: Email recipient73        :param sender: who to send email as (see :py:data:`SECURITY_EMAIL_SENDER`)74        :param body: the rendered body (text)75        :param html: the rendered body (html)76        :param kwargs: the entire context77 78        It is possible that sender is a lazy_string for localization (unlikely but..)79        so we cast to str() here to force localization.80        """81 82        if current_app.extensions.get("mailman", None):83            from flask_mailman import EmailMultiAlternatives, Mail84 85            # Flask-Mailman doesn't appear to take a tuple - a bug has been filed86            # but not sure they will fix it (parts of Flask-Mailman work - but not87            # the actual email headers).88            if isinstance(sender, tuple) and len(sender) == 2:89                #  sender = (str(sender[0]), str(sender[1]))90                sender = f"{str(sender[0])} <{str(sender[1])}>"91            else:92                sender = str(sender)93 94            mail: Mail = current_app.extensions.get("mailman")95            with mail.get_connection() as connection:96                msg = EmailMultiAlternatives(97                    subject,98                    body=body,99                    from_email=sender,100                    to=[recipient],101                    connection=connection,102                )103                if html:104                    msg.attach_alternative(html, "text/html")105                msg.send()106 107        elif current_app.extensions.get("mail", None):  # pragma: no cover108            from flask_mail import Message109 110            # In Flask-Mail, sender can be a two element tuple -- (name, address)111            if isinstance(sender, tuple) and len(sender) == 2:112                sender = (str(sender[0]), str(sender[1]))113            else:114                sender = str(sender)115            msg = Message(subject, sender=sender, recipients=[recipient])116            msg.body = body117            msg.html = html118 119            mail = current_app.extensions.get("mail")120            mail.send(msg)  # type: ignore121 122        else:  # pragma: no cover123            raise ValueError("No email extension configured")124 125    def normalize(self, email: str) -> str:126        """127        Given an input email - return a normalized version or128        raise EmailValidateException if field value isn't syntactically valid.129 130        This is called by forms that use email as an identity to be looked up.131 132        Must be called in app context and uses :py:data:`SECURITY_EMAIL_VALIDATOR_ARGS`133        config variable to pass any relevant arguments to134        email_validator.validate_email() method.135 136        This defaults to NOT checking for deliverability (i.e. DNS checks).137        """138        validator_args = config_value("EMAIL_VALIDATOR_ARGS") or {}139        validator_args["check_deliverability"] = False140        try:141            valid = email_validator.validate_email(email, **validator_args)142            return valid.normalized143        except ValueError:144            raise EmailValidateException(get_message("INVALID_EMAIL_ADDRESS")[0])145 146    def validate(self, email: str) -> str:147        """148        Validate the given email.149        If valid, the normalized version is returned.150        This is used by forms/views that require an email that likely can have an151        actual email sent to it.152 153        Must be called in app context and uses :py:data:`SECURITY_EMAIL_VALIDATOR_ARGS`154        config variable to pass any relevant arguments to155        email_validator.validate_email() method.156 157        EmailValidationException is thrown on invalid email.158        """159 160        validator_args = config_value("EMAIL_VALIDATOR_ARGS") or {}161        try:162            valid = email_validator.validate_email(email, **validator_args)163            return valid.normalized164        except ValueError:165            raise EmailValidateException(get_message("INVALID_EMAIL_ADDRESS")[0])166 
codekingpro/portable-devtools · Team Ai