Base Email Processor

BaseEmailProcessor

Source code in easy_email/processors/base.py
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
class BaseEmailProcessor:
    def __init__(self, subject, email_body, recipient_list,
            from_email=None, fail_silently=True, **kwargs):
        """
        Initializes the email processor with the given email details and optional parameters.

        Args:
        - subject (str): The subject of the email.
        - email_body (str): The body content of the email (plain text).
        - recipient_list (list): A list of email addresses to which the email will be sent.
        - from_email (str, optional): The sender's email address. If not provided, a default will be used.
        - fail_silently (bool, optional): A flag that determines whether to suppress exceptions if an error occurs during email sending. Default is True (suppress errors).

        Keyword Arguments (kwargs):
        - files (list, optional): A list of `Attachment` objects that will be included with the email. The list is passed via `kwargs`.

        Attributes:
        - subject (str): The email subject.
        - recipient_list (list): The list of recipients for the email.
        - from_email (str): The sender's email address.
        - fail_silently (bool): Whether to fail silently or raise errors when sending the email.
        - message (str): The plain text body of the email.
        - html_message (str): The HTML body of the email (same as `message` in this case).
        - send_time (datetime, optional): The time at which the email should be sent. Defaults to None (send immediately).
        """
        self.subject = subject
        self.recipient_list = recipient_list
        self.from_email = from_email
        self.fail_silently = fail_silently
        self.message = email_body
        self.html_message = email_body
        self.send_time = None
        self.kwargs = kwargs

    def get_connection(self):
        connection_data = self.get_connection_data()
        return get_connection(**connection_data)

    def get_send_time(self, raw_send_time=None):
        raise NotImplementedError("subclass must implement this method: `get_send_time`")

    def send(self, send_time: Optional[Union[None, timezone.datetime, int]]=None):
        """
        Arguments:
        - send_time (Optional[Union[None, datetime, int]]): Determines when to send the email.
            - None: Sends the email instantly.
            - datetime: Sends the email at the specified future datetime.
            - int: Sends the email after the specified number of seconds (delay).

        If the datetime is in the past, the function will raise an error. If an integer is provided, it will be interpreted as a delay in seconds, and the email will be sent after that duration.
        """
        send_time = self.get_send_time(send_time)
        self._send(send_time)

    def _process_files(self) -> List[Attachment]:
        """
        This method processes the 'files' parameter from kwargs, ensuring that all
        files provided are instances of the Attachment class. It returns a list of valid 
        Attachment objects after performing the check.

        Input:
        - No explicit input, uses the `files` keyword argument passed to the class.

        Output:
        - List of `Attachment` objects (valid files). If any of the files are not 
        `Attachment` objects, an exception is raised.

        Raises:
        - InvalidFileFormat: If any item in the `files` list is not an instance of the 
        `Attachment` class.
        """
        # Extract the "files" from kwargs, default to an empty list if not provided
        attachments = self.kwargs.pop("files", []) or []

        # Check that all items in attachments are instances of Attachment
        for attachment in attachments:
            if not isinstance(attachment, Attachment):
                # Raise an error if the file is not an instance of the Attachment class
                raise InvalidFileFormat("All files must be instances of the Attachment class")

        # Return the list of valid Attachment objects
        return attachments

    def _send(self, send_time):
        connection = self.get_connection()

        attachments = self._process_files()
        email_obj = self._save_email(send_time)

        try:
            msg = EmailMultiAlternatives(
                subject=self.subject,
                body=self.message,
                from_email=self.from_email or self.get_default_from_email(),
                to=self.recipient_list,
                connection=connection,
                cc=self.kwargs.get('cc'),
            )
            msg.attach_alternative(self.html_message, "text/html")
            # attach the files.
            for attachment in attachments:
                msg.attach(
                    filename=attachment.file.name,
                    content=attachment.file.read(),
                    mimetype=filetype.guess_mime(attachment.file.read()),
                )
            msg.send(self.fail_silently)

            # update email status
            email_obj.status = EmailStatus.SUCCESS
            email_obj.save()
        except Exception as e:
            email_obj.status = EmailStatus.ERROR
            email_obj.logs = "".join(traceback.format_exception(None, e, e.__traceback__))
            email_obj.save()

    def get_connection_data(self):
        connection_data = {
            "host": settings.EMAIL_HOST,
            "port": settings.EMAIL_PORT,
            "username": settings.EMAIL_HOST_USER,
            "password": settings.EMAIL_HOST_PASSWORD,
            "use_tls": settings.EMAIL_USE_TLS,
        }
        return connection_data

    def get_default_from_email(self):
        return settings.DEFAULT_FROM_EMAIL

    def _save_email(self, send_time):
        attachment_objs = self._process_files()
        email_obj = Email.objects.create(
            subject=self.subject,
            body=self.message,
            recipients=self.recipient_list,
            from_email=self.from_email or self.get_default_from_email(),
            cc=self.kwargs.get('cc'),
        )

        email_obj.send_time = send_time
        email_obj.attachments.set(attachment_objs)
        email_obj.save()
        return email_obj

__init__(subject, email_body, recipient_list, from_email=None, fail_silently=True, **kwargs)

Initializes the email processor with the given email details and optional parameters.

Args: - subject (str): The subject of the email. - email_body (str): The body content of the email (plain text). - recipient_list (list): A list of email addresses to which the email will be sent. - from_email (str, optional): The sender’s email address. If not provided, a default will be used. - fail_silently (bool, optional): A flag that determines whether to suppress exceptions if an error occurs during email sending. Default is True (suppress errors).

Keyword Arguments (kwargs): - files (list, optional): A list of Attachment objects that will be included with the email. The list is passed via kwargs.

Attributes: - subject (str): The email subject. - recipient_list (list): The list of recipients for the email. - from_email (str): The sender’s email address. - fail_silently (bool): Whether to fail silently or raise errors when sending the email. - message (str): The plain text body of the email. - html_message (str): The HTML body of the email (same as message in this case). - send_time (datetime, optional): The time at which the email should be sent. Defaults to None (send immediately).

Source code in easy_email/processors/base.py
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
def __init__(self, subject, email_body, recipient_list,
        from_email=None, fail_silently=True, **kwargs):
    """
    Initializes the email processor with the given email details and optional parameters.

    Args:
    - subject (str): The subject of the email.
    - email_body (str): The body content of the email (plain text).
    - recipient_list (list): A list of email addresses to which the email will be sent.
    - from_email (str, optional): The sender's email address. If not provided, a default will be used.
    - fail_silently (bool, optional): A flag that determines whether to suppress exceptions if an error occurs during email sending. Default is True (suppress errors).

    Keyword Arguments (kwargs):
    - files (list, optional): A list of `Attachment` objects that will be included with the email. The list is passed via `kwargs`.

    Attributes:
    - subject (str): The email subject.
    - recipient_list (list): The list of recipients for the email.
    - from_email (str): The sender's email address.
    - fail_silently (bool): Whether to fail silently or raise errors when sending the email.
    - message (str): The plain text body of the email.
    - html_message (str): The HTML body of the email (same as `message` in this case).
    - send_time (datetime, optional): The time at which the email should be sent. Defaults to None (send immediately).
    """
    self.subject = subject
    self.recipient_list = recipient_list
    self.from_email = from_email
    self.fail_silently = fail_silently
    self.message = email_body
    self.html_message = email_body
    self.send_time = None
    self.kwargs = kwargs

send(send_time=None)

  • send_time (Optional[Union[None, datetime, int]]): Determines when to send the email.
    • None: Sends the email instantly.
    • datetime: Sends the email at the specified future datetime.
    • int: Sends the email after the specified number of seconds (delay).

If the datetime is in the past, the function will raise an error. If an integer is provided, it will be interpreted as a delay in seconds, and the email will be sent after that duration.

Source code in easy_email/processors/base.py
53
54
55
56
57
58
59
60
61
62
63
64
def send(self, send_time: Optional[Union[None, timezone.datetime, int]]=None):
    """
    Arguments:
    - send_time (Optional[Union[None, datetime, int]]): Determines when to send the email.
        - None: Sends the email instantly.
        - datetime: Sends the email at the specified future datetime.
        - int: Sends the email after the specified number of seconds (delay).

    If the datetime is in the past, the function will raise an error. If an integer is provided, it will be interpreted as a delay in seconds, and the email will be sent after that duration.
    """
    send_time = self.get_send_time(send_time)
    self._send(send_time)