aboutsummaryrefslogtreecommitdiff
path: root/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail
diff options
context:
space:
mode:
Diffstat (limited to '.venv/lib/python3.12/site-packages/sendgrid/helpers/mail')
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/__init__.py63
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/amp_html_content.py59
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/asm.py80
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/attachment.py218
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/batch_id.py50
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/bcc_email.py5
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/bcc_settings.py72
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/bcc_settings_email.py40
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/bypass_bounce_management.py48
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/bypass_list_management.py48
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/bypass_spam_management.py47
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/bypass_unsubscribe_management.py49
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/category.py40
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/cc_email.py5
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/click_tracking.py71
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/content.py81
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/content_id.py50
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/custom_arg.py94
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/disposition.py72
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/dynamic_template_data.py73
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/email.py228
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/exceptions.py65
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/file_content.py39
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/file_name.py39
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/file_type.py39
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/footer_html.py39
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/footer_settings.py94
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/footer_text.py39
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/from_email.py5
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/ganalytics.py176
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/group_id.py39
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/groups_to_display.py48
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/header.py94
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/html_content.py59
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/ip_pool_name.py40
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/mail.py1041
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/mail_settings.py243
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/mime_type.py6
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/open_tracking.py80
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/open_tracking_substitution_tag.py49
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/personalization.py271
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/plain_text_content.py60
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/reply_to.py5
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/sandbox_mode.py44
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/section.py64
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/send_at.py79
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/spam_check.py112
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/spam_threshold.py53
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/spam_url.py44
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/subject.py69
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/subscription_html.py45
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/subscription_substitution_tag.py58
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/subscription_text.py45
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/subscription_tracking.py142
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/substitution.py90
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/template_id.py39
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/to_email.py5
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/tracking_settings.py134
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/utm_campaign.py40
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/utm_content.py40
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/utm_medium.py40
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/utm_source.py43
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/utm_term.py40
-rw-r--r--.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/validators.py69
64 files changed, 5358 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/__init__.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/__init__.py
new file mode 100644
index 00000000..358f2d91
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/__init__.py
@@ -0,0 +1,63 @@
+from .asm import Asm
+from .attachment import Attachment
+from .batch_id import BatchId
+from .bcc_email import Bcc
+from .bcc_settings import BccSettings
+from .bcc_settings_email import BccSettingsEmail
+from .bypass_bounce_management import BypassBounceManagement
+from .bypass_list_management import BypassListManagement
+from .bypass_spam_management import BypassSpamManagement
+from .bypass_unsubscribe_management import BypassUnsubscribeManagement
+from .category import Category
+from .cc_email import Cc
+from .click_tracking import ClickTracking
+from .content import Content
+from .content_id import ContentId
+from .custom_arg import CustomArg
+from .disposition import Disposition
+from .dynamic_template_data import DynamicTemplateData
+from .email import Email
+from .exceptions import SendGridException, ApiKeyIncludedException
+from .file_content import FileContent
+from .file_name import FileName
+from .file_type import FileType
+from .footer_settings import FooterSettings
+from .footer_text import FooterText
+from .footer_html import FooterHtml
+from .from_email import From
+from .ganalytics import Ganalytics
+from .group_id import GroupId
+from .groups_to_display import GroupsToDisplay
+from .header import Header
+from .html_content import HtmlContent
+from .amp_html_content import AmpHtmlContent
+from .ip_pool_name import IpPoolName
+from .mail_settings import MailSettings
+from .mail import Mail
+from .mime_type import MimeType
+from .open_tracking import OpenTracking
+from .open_tracking_substitution_tag import OpenTrackingSubstitutionTag
+from .personalization import Personalization
+from .plain_text_content import PlainTextContent
+from .reply_to import ReplyTo
+from .sandbox_mode import SandBoxMode
+from .section import Section
+from .send_at import SendAt
+from .spam_check import SpamCheck
+from .spam_threshold import SpamThreshold
+from .spam_url import SpamUrl
+from .subject import Subject
+from .subscription_tracking import SubscriptionTracking
+from .subscription_text import SubscriptionText
+from .subscription_html import SubscriptionHtml
+from .subscription_substitution_tag import SubscriptionSubstitutionTag
+from .substitution import Substitution
+from .template_id import TemplateId
+from .tracking_settings import TrackingSettings
+from .to_email import To
+from .utm_source import UtmSource
+from .utm_medium import UtmMedium
+from .utm_term import UtmTerm
+from .utm_content import UtmContent
+from .utm_campaign import UtmCampaign
+from .validators import ValidateApiKey
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/amp_html_content.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/amp_html_content.py
new file mode 100644
index 00000000..1a282053
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/amp_html_content.py
@@ -0,0 +1,59 @@
+from .content import Content
+from .validators import ValidateApiKey
+
+
+class AmpHtmlContent(Content):
+ """AMP HTML content to be included in your email."""
+
+ def __init__(self, content):
+ """Create an AMP HTML Content with the specified MIME type and content.
+
+ :param content: The AMP HTML content.
+ :type content: string
+ """
+ self._content = None
+ self._validator = ValidateApiKey()
+
+ if content is not None:
+ self.content = content
+
+ @property
+ def mime_type(self):
+ """The MIME type for AMP HTML content.
+
+ :rtype: string
+ """
+ return "text/x-amp-html"
+
+ @property
+ def content(self):
+ """The actual AMP HTML content.
+
+ :rtype: string
+ """
+ return self._content
+
+ @content.setter
+ def content(self, value):
+ """The actual AMP HTML content.
+
+ :param value: The actual AMP HTML content.
+ :type value: string
+ """
+ self._validator.validate_message_dict(value)
+ self._content = value
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this AmpContent.
+
+ :returns: This AmpContent, ready for use in a request body.
+ :rtype: dict
+ """
+ content = {}
+ if self.mime_type is not None:
+ content["type"] = self.mime_type
+
+ if self.content is not None:
+ content["value"] = self.content
+ return content
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/asm.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/asm.py
new file mode 100644
index 00000000..62db8372
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/asm.py
@@ -0,0 +1,80 @@
+from .group_id import GroupId
+from .groups_to_display import GroupsToDisplay
+
+
+class Asm(object):
+ """An object specifying unsubscribe behavior."""
+
+ def __init__(self, group_id, groups_to_display=None):
+ """Create an ASM with the given group_id and groups_to_display.
+
+ :param group_id: ID of an unsubscribe group
+ :type group_id: GroupId, int, required
+ :param groups_to_display: Unsubscribe groups to display
+ :type groups_to_display: GroupsToDisplay, list(int), optional
+ """
+ self._group_id = None
+ self._groups_to_display = None
+
+ if group_id is not None:
+ self.group_id = group_id
+
+ if groups_to_display is not None:
+ self.groups_to_display = groups_to_display
+
+ @property
+ def group_id(self):
+ """The unsubscribe group to associate with this email.
+
+ :rtype: GroupId
+ """
+ return self._group_id
+
+ @group_id.setter
+ def group_id(self, value):
+ """The unsubscribe group to associate with this email.
+
+ :param value: ID of an unsubscribe group
+ :type value: GroupId, int, required
+ """
+ if isinstance(value, GroupId):
+ self._group_id = value
+ else:
+ self._group_id = GroupId(value)
+
+ @property
+ def groups_to_display(self):
+ """The unsubscribe groups that you would like to be displayed on the
+ unsubscribe preferences page. Max of 25 groups.
+
+ :rtype: GroupsToDisplay
+ """
+ return self._groups_to_display
+
+ @groups_to_display.setter
+ def groups_to_display(self, value):
+ """An array containing the unsubscribe groups that you would like to
+ be displayed on the unsubscribe preferences page. Max of 25 groups.
+
+ :param groups_to_display: Unsubscribe groups to display
+ :type groups_to_display: GroupsToDisplay, list(int), optional
+ """
+ if isinstance(value, GroupsToDisplay):
+ self._groups_to_display = value
+ else:
+ self._groups_to_display = GroupsToDisplay(value)
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this ASM object.
+
+ :returns: This ASM object, ready for use in a request body.
+ :rtype: dict
+ """
+ asm = {}
+ if self.group_id is not None:
+ asm["group_id"] = self.group_id.get()
+
+ if self.groups_to_display is not None:
+ asm["groups_to_display"] = self.groups_to_display.get()
+ return asm
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/attachment.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/attachment.py
new file mode 100644
index 00000000..f8b53a68
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/attachment.py
@@ -0,0 +1,218 @@
+from .file_content import FileContent
+from .file_type import FileType
+from .file_name import FileName
+from .disposition import Disposition
+from .content_id import ContentId
+
+
+class Attachment(object):
+ """An attachment to be included with an email."""
+
+ def __init__(
+ self,
+ file_content=None,
+ file_name=None,
+ file_type=None,
+ disposition=None,
+ content_id=None):
+ """Create an Attachment
+
+ :param file_content: The Base64 encoded content of the attachment
+ :type file_content: FileContent, string
+ :param file_name: The filename of the attachment
+ :type file_name: FileName, string
+ :param file_type: The MIME type of the content you are attaching
+ :type file_type FileType, string, optional
+ :param disposition: The content-disposition of the attachment,
+ specifying display style. Specifies how you
+ would like the attachment to be displayed.
+ - "inline" results in the attached file being
+ displayed automatically within the message.
+ - "attachment" results in the attached file
+ requiring some action to display (e.g. opening
+ or downloading the file).
+ If unspecified, "attachment" is used. Must be one
+ of the two choices.
+ :type disposition: Disposition, string, optional
+ :param content_id: The content id for the attachment.
+ This is used when the Disposition is set to
+ "inline" and the attachment is an image, allowing
+ the file to be displayed within the email body.
+ :type content_id: ContentId, string, optional
+ """
+ self._file_content = None
+ self._file_type = None
+ self._file_name = None
+ self._disposition = None
+ self._content_id = None
+
+ if file_content is not None:
+ self.file_content = file_content
+
+ if file_type is not None:
+ self.file_type = file_type
+
+ if file_name is not None:
+ self.file_name = file_name
+
+ if disposition is not None:
+ self.disposition = disposition
+
+ if content_id is not None:
+ self.content_id = content_id
+
+ @property
+ def file_content(self):
+ """The Base64 encoded content of the attachment.
+
+ :rtype: FileContent
+ """
+ return self._file_content
+
+ @file_content.setter
+ def file_content(self, value):
+ """The Base64 encoded content of the attachment
+
+ :param value: The Base64 encoded content of the attachment
+ :type value: FileContent, string
+ """
+ if isinstance(value, FileContent):
+ self._file_content = value
+ else:
+ self._file_content = FileContent(value)
+
+ @property
+ def file_name(self):
+ """The file name of the attachment.
+
+ :rtype: FileName
+ """
+ return self._file_name
+
+ @file_name.setter
+ def file_name(self, value):
+ """The filename of the attachment
+
+ :param file_name: The filename of the attachment
+ :type file_name: FileName, string
+ """
+ if isinstance(value, FileName):
+ self._file_name = value
+ else:
+ self._file_name = FileName(value)
+
+ @property
+ def file_type(self):
+ """The MIME type of the content you are attaching.
+
+ :rtype: FileType
+ """
+ return self._file_type
+
+ @file_type.setter
+ def file_type(self, value):
+ """The MIME type of the content you are attaching
+
+ :param file_type: The MIME type of the content you are attaching
+ :type file_type FileType, string, optional
+ """
+ if isinstance(value, FileType):
+ self._file_type = value
+ else:
+ self._file_type = FileType(value)
+
+ @property
+ def disposition(self):
+ """The content-disposition of the attachment, specifying display style.
+
+ Specifies how you would like the attachment to be displayed.
+ - "inline" results in the attached file being displayed automatically
+ within the message.
+ - "attachment" results in the attached file requiring some action to
+ display (e.g. opening or downloading the file).
+ If unspecified, "attachment" is used. Must be one of the two choices.
+
+ :rtype: Disposition
+ """
+ return self._disposition
+
+ @disposition.setter
+ def disposition(self, value):
+ """The content-disposition of the attachment, specifying display style.
+
+ Specifies how you would like the attachment to be displayed.
+ - "inline" results in the attached file being displayed automatically
+ within the message.
+ - "attachment" results in the attached file requiring some action to
+ display (e.g. opening or downloading the file).
+ If unspecified, "attachment" is used. Must be one of the two choices.
+
+ :param disposition: The content-disposition of the attachment,
+ specifying display style. Specifies how you would
+ like the attachment to be displayed.
+ - "inline" results in the attached file being
+ displayed automatically within the message.
+ - "attachment" results in the attached file
+ requiring some action to display (e.g. opening
+ or downloading the file).
+ If unspecified, "attachment" is used. Must be one
+ of the two choices.
+ :type disposition: Disposition, string, optional
+ """
+ if isinstance(value, Disposition):
+ self._disposition = value
+ else:
+ self._disposition = Disposition(value)
+
+ @property
+ def content_id(self):
+ """The content id for the attachment.
+
+ This is used when the disposition is set to "inline" and the attachment
+ is an image, allowing the file to be displayed within the email body.
+
+ :rtype: string
+ """
+ return self._content_id
+
+ @content_id.setter
+ def content_id(self, value):
+ """The content id for the attachment.
+
+ This is used when the disposition is set to "inline" and the attachment
+ is an image, allowing the file to be displayed within the email body.
+
+ :param content_id: The content id for the attachment.
+ This is used when the Disposition is set to "inline"
+ and the attachment is an image, allowing the file to
+ be displayed within the email body.
+ :type content_id: ContentId, string, optional
+ """
+ if isinstance(value, ContentId):
+ self._content_id = value
+ else:
+ self._content_id = ContentId(value)
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this Attachment.
+
+ :returns: This Attachment, ready for use in a request body.
+ :rtype: dict
+ """
+ attachment = {}
+ if self.file_content is not None:
+ attachment["content"] = self.file_content.get()
+
+ if self.file_type is not None:
+ attachment["type"] = self.file_type.get()
+
+ if self.file_name is not None:
+ attachment["filename"] = self.file_name.get()
+
+ if self.disposition is not None:
+ attachment["disposition"] = self.disposition.get()
+
+ if self.content_id is not None:
+ attachment["content_id"] = self.content_id.get()
+ return attachment
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/batch_id.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/batch_id.py
new file mode 100644
index 00000000..a4c0f8e9
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/batch_id.py
@@ -0,0 +1,50 @@
+class BatchId(object):
+ """This ID represents a batch of emails to be sent at the same time.
+ Including a batch_id in your request allows you include this email
+ in that batch, and also enables you to cancel or pause the delivery
+ of that batch. For more information, see
+ https://sendgrid.com/docs/API_Reference/Web_API_v3/cancel_schedule_send.
+ """
+ def __init__(self, batch_id=None):
+ """Create a batch ID.
+
+ :param batch_id: Batch Id
+ :type batch_id: string
+ """
+ self._batch_id = None
+
+ if batch_id is not None:
+ self.batch_id = batch_id
+
+ @property
+ def batch_id(self):
+ """The batch ID.
+
+ :rtype: string
+ """
+ return self._batch_id
+
+ @batch_id.setter
+ def batch_id(self, value):
+ """The batch ID.
+
+ :param value: Batch Id
+ :type value: string
+ """
+ self._batch_id = value
+
+ def __str__(self):
+ """Get a JSON representation of this object.
+
+ :rtype: string
+ """
+ return str(self.get())
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this BatchId object.
+
+ :returns: The BatchId, ready for use in a request body.
+ :rtype: string
+ """
+ return self.batch_id
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/bcc_email.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/bcc_email.py
new file mode 100644
index 00000000..e78f6703
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/bcc_email.py
@@ -0,0 +1,5 @@
+from .email import Email
+
+
+class Bcc(Email):
+ """A bcc email address with an optional name."""
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/bcc_settings.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/bcc_settings.py
new file mode 100644
index 00000000..eeb8ba10
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/bcc_settings.py
@@ -0,0 +1,72 @@
+class BccSettings(object):
+ """Settings object for automatic BCC.
+
+ This allows you to have a blind carbon copy automatically sent to the
+ specified email address for every email that is sent.
+ """
+
+ def __init__(self, enable=None, email=None):
+ """Create a BCCSettings.
+
+ :param enable: Whether this BCCSettings is applied to sent emails.
+ :type enable: boolean, optional
+ :param email: Who should be BCCed.
+ :type email: BccSettingEmail, optional
+ """
+ self._enable = None
+ self._email = None
+
+ if enable is not None:
+ self.enable = enable
+
+ if email is not None:
+ self.email = email
+
+ @property
+ def enable(self):
+ """Indicates if this setting is enabled.
+
+ :rtype: boolean
+ """
+ return self._enable
+
+ @enable.setter
+ def enable(self, value):
+ """Indicates if this setting is enabled.
+
+ :type param: Indicates if this setting is enabled.
+ :type value: boolean
+ """
+ self._enable = value
+
+ @property
+ def email(self):
+ """The email address that you would like to receive the BCC.
+
+ :rtype: string
+ """
+ return self._email
+
+ @email.setter
+ def email(self, value):
+ """The email address that you would like to receive the BCC.
+
+ :param value: The email address that you would like to receive the BCC.
+ :type value: string
+ """
+ self._email = value
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this BCCSettings.
+
+ :returns: This BCCSettings, ready for use in a request body.
+ :rtype: dict
+ """
+ bcc_settings = {}
+ if self.enable is not None:
+ bcc_settings["enable"] = self.enable
+
+ if self.email is not None:
+ bcc_settings["email"] = self.email.get()
+ return bcc_settings
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/bcc_settings_email.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/bcc_settings_email.py
new file mode 100644
index 00000000..2c2847e2
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/bcc_settings_email.py
@@ -0,0 +1,40 @@
+class BccSettingsEmail(object):
+ """The BccSettingsEmail of an Attachment."""
+
+ def __init__(self, bcc_settings_email=None):
+ """Create a BccSettingsEmail object
+
+ :param bcc_settings_email: The email address that you would like to
+ receive the BCC
+ :type bcc_settings_email: string, optional
+ """
+ self._bcc_settings_email = None
+
+ if bcc_settings_email is not None:
+ self.bcc_settings_email = bcc_settings_email
+
+ @property
+ def bcc_settings_email(self):
+ """The email address that you would like to receive the BCC
+
+ :rtype: string
+ """
+ return self._bcc_settings_email
+
+ @bcc_settings_email.setter
+ def bcc_settings_email(self, value):
+ """The email address that you would like to receive the BCC
+
+ :param value: The email address that you would like to receive the BCC
+ :type value: string
+ """
+ self._bcc_settings_email = value
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this BccSettingsEmail.
+
+ :returns: This BccSettingsEmail, ready for use in a request body.
+ :rtype: string
+ """
+ return self.bcc_settings_email
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/bypass_bounce_management.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/bypass_bounce_management.py
new file mode 100644
index 00000000..b0a35105
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/bypass_bounce_management.py
@@ -0,0 +1,48 @@
+class BypassBounceManagement(object):
+ """Setting for Bypass Bounce Management
+
+
+ Allows you to bypass the bounce list to ensure that the email is delivered to recipients.
+ Spam report and unsubscribe lists will still be checked; addresses on these other lists
+ will not receive the message. This filter cannot be combined with the bypass_list_management filter.
+ """
+
+ def __init__(self, enable=None):
+ """Create a BypassBounceManagement.
+
+ :param enable: Whether emails should bypass bounce management.
+ :type enable: boolean, optional
+ """
+ self._enable = None
+
+ if enable is not None:
+ self.enable = enable
+
+ @property
+ def enable(self):
+ """Indicates if this setting is enabled.
+
+ :rtype: boolean
+ """
+ return self._enable
+
+ @enable.setter
+ def enable(self, value):
+ """Indicates if this setting is enabled.
+
+ :param value: Indicates if this setting is enabled.
+ :type value: boolean
+ """
+ self._enable = value
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this BypassBounceManagement.
+
+ :returns: This BypassBounceManagement, ready for use in a request body.
+ :rtype: dict
+ """
+ bypass_bounce_management = {}
+ if self.enable is not None:
+ bypass_bounce_management["enable"] = self.enable
+ return bypass_bounce_management
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/bypass_list_management.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/bypass_list_management.py
new file mode 100644
index 00000000..ac13e3d7
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/bypass_list_management.py
@@ -0,0 +1,48 @@
+class BypassListManagement(object):
+ """Setting for Bypass List Management
+
+ Allows you to bypass all unsubscribe groups and suppressions to ensure that
+ the email is delivered to every single recipient. This should only be used
+ in emergencies when it is absolutely necessary that every recipient
+ receives your email.
+ """
+
+ def __init__(self, enable=None):
+ """Create a BypassListManagement.
+
+ :param enable: Whether emails should bypass list management.
+ :type enable: boolean, optional
+ """
+ self._enable = None
+
+ if enable is not None:
+ self.enable = enable
+
+ @property
+ def enable(self):
+ """Indicates if this setting is enabled.
+
+ :rtype: boolean
+ """
+ return self._enable
+
+ @enable.setter
+ def enable(self, value):
+ """Indicates if this setting is enabled.
+
+ :param value: Indicates if this setting is enabled.
+ :type value: boolean
+ """
+ self._enable = value
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this BypassListManagement.
+
+ :returns: This BypassListManagement, ready for use in a request body.
+ :rtype: dict
+ """
+ bypass_list_management = {}
+ if self.enable is not None:
+ bypass_list_management["enable"] = self.enable
+ return bypass_list_management
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/bypass_spam_management.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/bypass_spam_management.py
new file mode 100644
index 00000000..9b2552eb
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/bypass_spam_management.py
@@ -0,0 +1,47 @@
+class BypassSpamManagement(object):
+ """Setting for Bypass Spam Management
+
+ Allows you to bypass the spam report list to ensure that the email is delivered to recipients.
+ Bounce and unsubscribe lists will still be checked; addresses on these other lists will not
+ receive the message. This filter cannot be combined with the bypass_list_management filter.
+ """
+
+ def __init__(self, enable=None):
+ """Create a BypassSpamManagement.
+
+ :param enable: Whether emails should bypass spam management.
+ :type enable: boolean, optional
+ """
+ self._enable = None
+
+ if enable is not None:
+ self.enable = enable
+
+ @property
+ def enable(self):
+ """Indicates if this setting is enabled.
+
+ :rtype: boolean
+ """
+ return self._enable
+
+ @enable.setter
+ def enable(self, value):
+ """Indicates if this setting is enabled.
+
+ :param value: Indicates if this setting is enabled.
+ :type value: boolean
+ """
+ self._enable = value
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this BypassSpamManagement.
+
+ :returns: This BypassSpamManagement, ready for use in a request body.
+ :rtype: dict
+ """
+ bypass_spam_management = {}
+ if self.enable is not None:
+ bypass_spam_management["enable"] = self.enable
+ return bypass_spam_management
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/bypass_unsubscribe_management.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/bypass_unsubscribe_management.py
new file mode 100644
index 00000000..4867fac2
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/bypass_unsubscribe_management.py
@@ -0,0 +1,49 @@
+class BypassUnsubscribeManagement(object):
+ """Setting for Bypass Unsubscribe Management
+
+
+ Allows you to bypass the global unsubscribe list to ensure that the email is delivered to recipients.
+ Bounce and spam report lists will still be checked; addresses on these other lists will not receive
+ the message. This filter applies only to global unsubscribes and will not bypass group unsubscribes.
+ This filter cannot be combined with the bypass_list_management filter.
+ """
+
+ def __init__(self, enable=None):
+ """Create a BypassUnsubscribeManagement.
+
+ :param enable: Whether emails should bypass unsubscribe management.
+ :type enable: boolean, optional
+ """
+ self._enable = None
+
+ if enable is not None:
+ self.enable = enable
+
+ @property
+ def enable(self):
+ """Indicates if this setting is enabled.
+
+ :rtype: boolean
+ """
+ return self._enable
+
+ @enable.setter
+ def enable(self, value):
+ """Indicates if this setting is enabled.
+
+ :param value: Indicates if this setting is enabled.
+ :type value: boolean
+ """
+ self._enable = value
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this BypassUnsubscribeManagement.
+
+ :returns: This BypassUnsubscribeManagement, ready for use in a request body.
+ :rtype: dict
+ """
+ bypass_unsubscribe_management = {}
+ if self.enable is not None:
+ bypass_unsubscribe_management["enable"] = self.enable
+ return bypass_unsubscribe_management
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/category.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/category.py
new file mode 100644
index 00000000..0a6394c2
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/category.py
@@ -0,0 +1,40 @@
+class Category(object):
+ """A category name for this message."""
+
+ def __init__(self, name=None):
+ """Create a Category.
+
+ :param name: The name of this category
+ :type name: string, optional
+ """
+ self._name = None
+
+ if name is not None:
+ self.name = name
+
+ @property
+ def name(self):
+ """The name of this Category. Must be less than 255 characters.
+
+ :rtype: string
+ """
+ return self._name
+
+ @name.setter
+ def name(self, value):
+ """The name of this Category. Must be less than 255 characters.
+
+ :param value: The name of this Category. Must be less than 255
+ characters.
+ :type value: string
+ """
+ self._name = value
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this Category.
+
+ :returns: This Category, ready for use in a request body.
+ :rtype: string
+ """
+ return self.name
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/cc_email.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/cc_email.py
new file mode 100644
index 00000000..77b8ff28
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/cc_email.py
@@ -0,0 +1,5 @@
+from .email import Email
+
+
+class Cc(Email):
+ """A cc email address with an optional name."""
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/click_tracking.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/click_tracking.py
new file mode 100644
index 00000000..edfba41e
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/click_tracking.py
@@ -0,0 +1,71 @@
+class ClickTracking(object):
+ """Allows you to track whether a recipient clicked a link in your email."""
+
+ def __init__(self, enable=None, enable_text=None):
+ """Create a ClickTracking to track clicked links in your email.
+
+ :param enable: Whether click tracking is enabled
+ :type enable: boolean, optional
+ :param enable_text: If click tracking is on in your email's text/plain.
+ :type enable_text: boolean, optional
+ """
+ self._enable = None
+ self._enable_text = None
+
+ if enable is not None:
+ self.enable = enable
+
+ if enable_text is not None:
+ self.enable_text = enable_text
+
+ @property
+ def enable(self):
+ """Indicates if this setting is enabled.
+
+ :rtype: boolean
+ """
+ return self._enable
+
+ @enable.setter
+ def enable(self, value):
+ """Indicates if this setting is enabled.
+
+ :param value: Indicates if this setting is enabled.
+ :type value: boolean
+ """
+ self._enable = value
+
+ @property
+ def enable_text(self):
+ """Indicates if this setting should be included in the text/plain
+ portion of your email.
+
+ :rtype: boolean
+ """
+ return self._enable_text
+
+ @enable_text.setter
+ def enable_text(self, value):
+ """Indicates if this setting should be included in the text/plain
+ portion of your email.
+
+ :param value: Indicates if this setting should be included in the
+ text/plain portion of your email.
+ :type value: boolean
+ """
+ self._enable_text = value
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this ClickTracking.
+
+ :returns: This ClickTracking, ready for use in a request body.
+ :rtype: dict
+ """
+ click_tracking = {}
+ if self.enable is not None:
+ click_tracking["enable"] = self.enable
+
+ if self.enable_text is not None:
+ click_tracking["enable_text"] = self.enable_text
+ return click_tracking
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/content.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/content.py
new file mode 100644
index 00000000..618eee91
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/content.py
@@ -0,0 +1,81 @@
+from .validators import ValidateApiKey
+
+
+
+class Content(object):
+ """Content to be included in your email.
+
+ You must specify at least one mime type in the Contents of your email.
+ """
+
+ def __init__(self, mime_type, content):
+ """Create a Content with the specified MIME type and content.
+
+ :param mime_type: MIME type of this Content (e.g. "text/plain").
+ :type mime_type: string
+ :param content: The actual content.
+ :type content: string
+ """
+ self._mime_type = None
+ self._content = None
+ self._validator = ValidateApiKey()
+
+ if mime_type is not None:
+ self.mime_type = mime_type
+
+ if content is not None:
+ self.content = content
+
+ @property
+ def mime_type(self):
+ """The MIME type of the content you are including in your email.
+ For example, "text/plain" or "text/html" or "text/x-amp-html".
+
+ :rtype: string
+ """
+ return self._mime_type
+
+ @mime_type.setter
+ def mime_type(self, value):
+ """The MIME type of the content you are including in your email.
+ For example, "text/plain" or "text/html" or "text/x-amp-html".
+
+ :param value: The MIME type of the content you are including in your
+ email.
+ For example, "text/plain" or "text/html" or "text/x-amp-html".
+ :type value: string
+ """
+ self._mime_type = value
+
+ @property
+ def content(self):
+ """The actual content (of the specified mime type).
+
+ :rtype: string
+ """
+ return self._content
+
+ @content.setter
+ def content(self, value):
+ """The actual content (of the specified mime type).
+
+ :param value: The actual content (of the specified mime type).
+ :type value: string
+ """
+ self._validator.validate_message_dict(value)
+ self._content = value
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this Content.
+
+ :returns: This Content, ready for use in a request body.
+ :rtype: dict
+ """
+ content = {}
+ if self.mime_type is not None:
+ content["type"] = self.mime_type
+
+ if self.content is not None:
+ content["value"] = self.content
+ return content
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/content_id.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/content_id.py
new file mode 100644
index 00000000..0fff3010
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/content_id.py
@@ -0,0 +1,50 @@
+class ContentId(object):
+ """The ContentId of an Attachment."""
+
+ def __init__(self, content_id=None):
+ """Create a ContentId object
+
+ :param content_id: The content id for the attachment.
+ This is used when the Disposition is set to "inline"
+ and the attachment is an image, allowing the file to
+ be displayed within the email body.
+ :type content_id: string, optional
+ """
+ self._content_id = None
+
+ if content_id is not None:
+ self.content_id = content_id
+
+ @property
+ def content_id(self):
+ """The content id for the attachment.
+ This is used when the Disposition is set to "inline" and the
+ attachment is an image, allowing the file to be displayed within
+ the email body.
+
+ :rtype: string
+ """
+ return self._content_id
+
+ @content_id.setter
+ def content_id(self, value):
+ """The content id for the attachment.
+ This is used when the Disposition is set to "inline" and the
+ attachment is an image, allowing the file to be displayed within
+ the email body.
+
+ :param value: The content id for the attachment.
+ This is used when the Disposition is set to "inline" and the attachment
+ is an image, allowing the file to be displayed within the email body.
+ :type value: string
+ """
+ self._content_id = value
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this ContentId.
+
+ :returns: This ContentId, ready for use in a request body.
+ :rtype: string
+ """
+ return self.content_id
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/custom_arg.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/custom_arg.py
new file mode 100644
index 00000000..63b22557
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/custom_arg.py
@@ -0,0 +1,94 @@
+class CustomArg(object):
+ """Values that will be carried along with the email and its activity data.
+
+ Substitutions will not be made on custom arguments, so any string entered
+ into this parameter will be assumed to be the custom argument that you
+ would like to be used. Top-level CustomArgs may be overridden by ones in a
+ Personalization. May not exceed 10,000 bytes.
+ """
+
+ def __init__(self, key=None, value=None, p=None):
+ """Create a CustomArg with the given key and value.
+
+ :param key: Key for this CustomArg
+ :type key: string, optional
+ :param value: Value of this CustomArg
+ :type value: string, optional
+ :param p: p is the Personalization object or Personalization
+ object index
+ :type p: Personalization, integer, optional
+ """
+ self._key = None
+ self._value = None
+ self._personalization = None
+
+ if key is not None:
+ self.key = key
+ if value is not None:
+ self.value = value
+ if p is not None:
+ self.personalization = p
+
+ @property
+ def key(self):
+ """Key for this CustomArg.
+
+ :rtype: string
+ """
+ return self._key
+
+ @key.setter
+ def key(self, value):
+ """Key for this CustomArg.
+
+ :param value: Key for this CustomArg.
+ :type value: string
+ """
+ self._key = value
+
+ @property
+ def value(self):
+ """Value of this CustomArg.
+
+ :rtype: string
+ """
+ return self._value
+
+ @value.setter
+ def value(self, value):
+ """Value of this CustomArg.
+
+ :param value: Value of this CustomArg.
+ :type value: string
+ """
+ self._value = value
+
+ @property
+ def personalization(self):
+ """The Personalization object or Personalization object index
+
+ :rtype: Personalization, integer
+ """
+ return self._personalization
+
+ @personalization.setter
+ def personalization(self, value):
+ """The Personalization object or Personalization object index
+
+ :param value: The Personalization object or Personalization object
+ index
+ :type value: Personalization, integer
+ """
+ self._personalization = value
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this CustomArg.
+
+ :returns: This CustomArg, ready for use in a request body.
+ :rtype: dict
+ """
+ custom_arg = {}
+ if self.key is not None and self.value is not None:
+ custom_arg[self.key] = self.value
+ return custom_arg
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/disposition.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/disposition.py
new file mode 100644
index 00000000..a0bdc354
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/disposition.py
@@ -0,0 +1,72 @@
+class Disposition(object):
+ """The content-disposition of the Attachment specifying how you would like
+ the attachment to be displayed."""
+
+ def __init__(self, disposition=None):
+ """Create a Disposition object
+
+ :param disposition: The content-disposition of the attachment,
+ specifying display style.
+ Specifies how you would like the attachment to be
+ displayed.
+ - "inline" results in the attached file being
+ displayed automatically within the message.
+ - "attachment" results in the attached file
+ requiring some action to display (e.g. opening
+ or downloading the file).
+ If unspecified, "attachment" is used. Must be one
+ of the two choices.
+ :type disposition: string, optional
+ """
+ self._disposition = None
+
+ if disposition is not None:
+ self.disposition = disposition
+
+ @property
+ def disposition(self):
+ """The content-disposition of the attachment, specifying display style.
+ Specifies how you would like the attachment to be displayed.
+ - "inline" results in the attached file being displayed
+ automatically within the message.
+ - "attachment" results in the attached file requiring some action to
+ display (e.g. opening or downloading the file).
+ If unspecified, "attachment" is used. Must be one of the two
+ choices.
+
+ :rtype: string
+ """
+ return self._disposition
+
+ @disposition.setter
+ def disposition(self, value):
+ """The content-disposition of the attachment, specifying display style.
+ Specifies how you would like the attachment to be displayed.
+ - "inline" results in the attached file being displayed
+ automatically within the message.
+ - "attachment" results in the attached file requiring some action to
+ display (e.g. opening or downloading the file).
+ If unspecified, "attachment" is used. Must be one of the two
+ choices.
+
+ :param value: The content-disposition of the attachment, specifying
+ display style.
+ Specifies how you would like the attachment to be displayed.
+ - "inline" results in the attached file being displayed
+ automatically within the message.
+ - "attachment" results in the attached file requiring some action to
+ display (e.g. opening or downloading the file).
+ If unspecified, "attachment" is used. Must be one of the two
+ choices.
+ :type value: string
+ """
+ self._disposition = value
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this Disposition.
+
+ :returns: This Disposition, ready for use in a request body.
+ :rtype: string
+ """
+ return self.disposition
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/dynamic_template_data.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/dynamic_template_data.py
new file mode 100644
index 00000000..e12967b7
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/dynamic_template_data.py
@@ -0,0 +1,73 @@
+class DynamicTemplateData(object):
+ """To send a dynamic template, specify the template ID with the
+ template_id parameter.
+ """
+
+ def __init__(self, dynamic_template_data=None, p=0):
+ """Data for a transactional template.
+ Should be JSON-serializable structure.
+
+ :param dynamic_template_data: Data for a transactional template.
+ :type dynamic_template_data: A JSON-serializable structure
+ :param name: p is the Personalization object or Personalization object
+ index
+ :type name: Personalization, integer, optional
+ """
+ self._dynamic_template_data = None
+ self._personalization = None
+
+ if dynamic_template_data is not None:
+ self.dynamic_template_data = dynamic_template_data
+ if p is not None:
+ self.personalization = p
+
+ @property
+ def dynamic_template_data(self):
+ """Data for a transactional template.
+
+ :rtype: A JSON-serializable structure
+ """
+ return self._dynamic_template_data
+
+ @dynamic_template_data.setter
+ def dynamic_template_data(self, value):
+ """Data for a transactional template.
+
+ :param value: Data for a transactional template.
+ :type value: A JSON-serializable structure
+ """
+ self._dynamic_template_data = value
+
+ @property
+ def personalization(self):
+ """The Personalization object or Personalization object index
+
+ :rtype: Personalization, integer
+ """
+ return self._personalization
+
+ @personalization.setter
+ def personalization(self, value):
+ """The Personalization object or Personalization object index
+
+ :param value: The Personalization object or Personalization object
+ index
+ :type value: Personalization, integer
+ """
+ self._personalization = value
+
+ def __str__(self):
+ """Get a JSON representation of this object.
+
+ :rtype: A JSON-serializable structure
+ """
+ return str(self.get())
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this DynamicTemplateData object.
+
+ :returns: Data for a transactional template.
+ :rtype: A JSON-serializable structure.
+ """
+ return self.dynamic_template_data
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/email.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/email.py
new file mode 100644
index 00000000..aeab26af
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/email.py
@@ -0,0 +1,228 @@
+try:
+ import rfc822
+except ImportError:
+ import email.utils as rfc822
+
+try:
+ basestring = basestring
+except NameError:
+ # Define basestring when Python >= 3.0
+ basestring = str
+
+
+class Email(object):
+ """An email address with an optional name."""
+
+ def __init__(self,
+ email=None,
+ name=None,
+ substitutions=None,
+ subject=None,
+ p=0,
+ dynamic_template_data=None):
+ """Create an Email with the given address and name.
+
+ Either fill the separate name and email fields, or pass all information
+ in the email parameter (e.g. email="dude Fella <example@example.com>").
+ :param email: Email address, or name and address in standard format.
+ :type email: string, optional
+ :param name: Name for this sender or recipient.
+ :type name: string, optional
+ :param substitutions: String substitutions to be applied to the email.
+ :type substitutions: list(Substitution), optional
+ :param subject: Subject for this sender or recipient.
+ :type subject: string, optional
+ :param p: p is the Personalization object or Personalization object
+ index
+ :type p: Personalization, integer, optional
+ :param dynamic_template_data: Data for a dynamic transactional template.
+ :type dynamic_template_data: DynamicTemplateData, optional
+ """
+ self._name = None
+ self._email = None
+ self._personalization = p
+
+ if email and not name:
+ # allows passing emails as "Example Name <example@example.com>"
+ self.parse_email(email)
+ else:
+ # allows backwards compatibility for Email(email, name)
+ if email is not None:
+ self.email = email
+
+ if name is not None:
+ self.name = name
+
+ # Note that these only apply to To Emails (see Personalization.add_to)
+ # and should be moved but have not been for compatibility.
+ self._substitutions = substitutions
+ self._dynamic_template_data = dynamic_template_data
+ self._subject = subject
+
+ @property
+ def name(self):
+ """Name associated with this email.
+
+ :rtype: string
+ """
+ return self._name
+
+ @name.setter
+ def name(self, value):
+ """Name associated with this email.
+
+ :param value: Name associated with this email.
+ :type value: string
+ """
+ if not (value is None or isinstance(value, basestring)):
+ raise TypeError('name must be of type string.')
+
+ self._name = value
+
+ @property
+ def email(self):
+ """Email address.
+
+ See http://tools.ietf.org/html/rfc3696#section-3 and its errata
+ http://www.rfc-editor.org/errata_search.php?rfc=3696 for information
+ on valid email addresses.
+
+ :rtype: string
+ """
+ return self._email
+
+ @email.setter
+ def email(self, value):
+ """Email address.
+
+ See http://tools.ietf.org/html/rfc3696#section-3 and its errata
+ http://www.rfc-editor.org/errata_search.php?rfc=3696 for information
+ on valid email addresses.
+
+ :param value: Email address.
+ See http://tools.ietf.org/html/rfc3696#section-3 and its errata
+ http://www.rfc-editor.org/errata_search.php?rfc=3696 for information
+ on valid email addresses.
+ :type value: string
+ """
+ self._email = value
+
+ @property
+ def substitutions(self):
+ """A list of Substitution objects. These substitutions will apply to
+ the text and html content of the body of your email, in addition
+ to the subject and reply-to parameters. The total collective size
+ of your substitutions may not exceed 10,000 bytes per
+ personalization object.
+
+ :rtype: list(Substitution)
+ """
+ return self._substitutions
+
+ @substitutions.setter
+ def substitutions(self, value):
+ """A list of Substitution objects. These substitutions will apply to
+ the text and html content of the body of your email, in addition to
+ the subject and reply-to parameters. The total collective size of
+ your substitutions may not exceed 10,000 bytes per personalization
+ object.
+
+ :param value: A list of Substitution objects. These substitutions will
+ apply to the text and html content of the body of your email, in
+ addition to the subject and reply-to parameters. The total collective
+ size of your substitutions may not exceed 10,000 bytes per
+ personalization object.
+ :type value: list(Substitution)
+ """
+ self._substitutions = value
+
+ @property
+ def dynamic_template_data(self):
+ """Data for a dynamic transactional template.
+
+ :rtype: DynamicTemplateData
+ """
+ return self._dynamic_template_data
+
+ @dynamic_template_data.setter
+ def dynamic_template_data(self, value):
+ """Data for a dynamic transactional template.
+
+ :param value: DynamicTemplateData
+ :type value: DynamicTemplateData
+ """
+ self._dynamic_template_data = value
+
+ @property
+ def subject(self):
+ """Subject for this sender or recipient.
+
+ :rtype: string
+ """
+ return self._subject
+
+ @subject.setter
+ def subject(self, value):
+ """Subject for this sender or recipient.
+
+ :param value: Subject for this sender or recipient.
+ :type value: string, optional
+ """
+ self._subject = value
+
+ @property
+ def personalization(self):
+ """The Personalization object or Personalization object index
+
+ :rtype: Personalization, integer
+ """
+ return self._personalization
+
+ @personalization.setter
+ def personalization(self, value):
+ """The Personalization object or Personalization object index
+
+ :param value: The Personalization object or Personalization object
+ index
+ :type value: Personalization, integer
+ """
+ self._personalization = value
+
+ def parse_email(self, email_info):
+ """Allows passing emails as "Example Name <example@example.com>"
+
+ :param email_info: Allows passing emails as
+ "Example Name <example@example.com>"
+ :type email_info: string
+ """
+ name, email = rfc822.parseaddr(email_info)
+
+ # more than likely a string was passed here instead of an email address
+ if "@" not in email:
+ name = email
+ email = None
+
+ if not name:
+ name = None
+
+ if not email:
+ email = None
+
+ self.name = name
+ self.email = email
+ return name, email
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this Email.
+
+ :returns: This Email, ready for use in a request body.
+ :rtype: dict
+ """
+ email = {}
+ if self.name is not None:
+ email["name"] = self.name
+
+ if self.email is not None:
+ email["email"] = self.email
+ return email
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/exceptions.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/exceptions.py
new file mode 100644
index 00000000..cbc31134
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/exceptions.py
@@ -0,0 +1,65 @@
+################################################################
+# Various types of extensible Twilio SendGrid related exceptions
+################################################################
+
+
+class SendGridException(Exception):
+ """Wrapper/default SendGrid-related exception"""
+ pass
+
+
+class ApiKeyIncludedException(SendGridException):
+ """Exception raised for when Twilio SendGrid API Key included in message text"""
+
+ def __init__(self,
+ expression="Email body",
+ message="Twilio SendGrid API Key detected"):
+ """Create an exception for when Twilio SendGrid API Key included in message text
+
+ :param expression: Input expression in which the error occurred
+ :type expression: string
+ :param message: Explanation of the error
+ :type message: string
+ """
+ self._expression = None
+ self._message = None
+
+ if expression is not None:
+ self.expression = expression
+
+ if message is not None:
+ self.message = message
+
+ @property
+ def expression(self):
+ """Input expression in which the error occurred
+
+ :rtype: string
+ """
+ return self._expression
+
+ @expression.setter
+ def expression(self, value):
+ """Input expression in which the error occurred
+
+ :param value: Input expression in which the error occurred
+ :type value: string
+ """
+ self._expression = value
+
+ @property
+ def message(self):
+ """Explanation of the error
+
+ :rtype: string
+ """
+ return self._message
+
+ @message.setter
+ def message(self, value):
+ """Explanation of the error
+
+ :param value: Explanation of the error
+ :type value: string
+ """
+ self._message = value
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/file_content.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/file_content.py
new file mode 100644
index 00000000..c1eb81fc
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/file_content.py
@@ -0,0 +1,39 @@
+class FileContent(object):
+ """The Base64 encoded content of an Attachment."""
+
+ def __init__(self, file_content=None):
+ """Create a FileContent object
+
+ :param file_content: The Base64 encoded content of the attachment
+ :type file_content: string, optional
+ """
+ self._file_content = None
+
+ if file_content is not None:
+ self.file_content = file_content
+
+ @property
+ def file_content(self):
+ """The Base64 encoded content of the attachment.
+
+ :rtype: string
+ """
+ return self._file_content
+
+ @file_content.setter
+ def file_content(self, value):
+ """The Base64 encoded content of the attachment.
+
+ :param value: The Base64 encoded content of the attachment.
+ :type value: string
+ """
+ self._file_content = value
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this FileContent.
+
+ :returns: This FileContent, ready for use in a request body.
+ :rtype: string
+ """
+ return self.file_content
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/file_name.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/file_name.py
new file mode 100644
index 00000000..3a4e3ff2
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/file_name.py
@@ -0,0 +1,39 @@
+class FileName(object):
+ """The filename of an Attachment."""
+
+ def __init__(self, file_name=None):
+ """Create a FileName object
+
+ :param file_name: The file name of the attachment
+ :type file_name: string, optional
+ """
+ self._file_name = None
+
+ if file_name is not None:
+ self.file_name = file_name
+
+ @property
+ def file_name(self):
+ """The file name of the attachment.
+
+ :rtype: string
+ """
+ return self._file_name
+
+ @file_name.setter
+ def file_name(self, value):
+ """The file name of the attachment.
+
+ :param value: The file name of the attachment.
+ :type value: string
+ """
+ self._file_name = value
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this FileName.
+
+ :returns: This FileName, ready for use in a request body.
+ :rtype: string
+ """
+ return self.file_name
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/file_type.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/file_type.py
new file mode 100644
index 00000000..a30e6edf
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/file_type.py
@@ -0,0 +1,39 @@
+class FileType(object):
+ """The MIME type of the content you are attaching to an Attachment."""
+
+ def __init__(self, file_type=None):
+ """Create a FileType object
+
+ :param file_type: The MIME type of the content you are attaching
+ :type file_type: string, optional
+ """
+ self._file_type = None
+
+ if file_type is not None:
+ self.file_type = file_type
+
+ @property
+ def file_type(self):
+ """The MIME type of the content you are attaching.
+
+ :rtype: string
+ """
+ return self._file_type
+
+ @file_type.setter
+ def file_type(self, mime_type):
+ """The MIME type of the content you are attaching.
+
+ :param mime_type: The MIME type of the content you are attaching.
+ :rtype mime_type: string
+ """
+ self._file_type = mime_type
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this FileType.
+
+ :returns: This FileType, ready for use in a request body.
+ :rtype: string
+ """
+ return self.file_type
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/footer_html.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/footer_html.py
new file mode 100644
index 00000000..c8b5ac1a
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/footer_html.py
@@ -0,0 +1,39 @@
+class FooterHtml(object):
+ """The HTML in a Footer."""
+
+ def __init__(self, footer_html=None):
+ """Create a FooterHtml object
+
+ :param footer_html: The html content of your footer.
+ :type footer_html: string, optional
+ """
+ self._footer_html = None
+
+ if footer_html is not None:
+ self.footer_html = footer_html
+
+ @property
+ def footer_html(self):
+ """The html content of your footer.
+
+ :rtype: string
+ """
+ return self._footer_html
+
+ @footer_html.setter
+ def footer_html(self, html):
+ """The html content of your footer.
+
+ :param html: The html content of your footer.
+ :type html: string
+ """
+ self._footer_html = html
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this FooterHtml.
+
+ :returns: This FooterHtml, ready for use in a request body.
+ :rtype: string
+ """
+ return self.footer_html
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/footer_settings.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/footer_settings.py
new file mode 100644
index 00000000..1b0efeb1
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/footer_settings.py
@@ -0,0 +1,94 @@
+class FooterSettings(object):
+ """The default footer that you would like included on every email."""
+
+ def __init__(self, enable=None, text=None, html=None):
+ """Create a default footer.
+
+ :param enable: Whether this footer should be applied.
+ :type enable: boolean, optional
+ :param text: Text content of this footer
+ :type text: FooterText, optional
+ :param html: HTML content of this footer
+ :type html: FooterHtml, optional
+ """
+ self._enable = None
+ self._text = None
+ self._html = None
+
+ if enable is not None:
+ self.enable = enable
+
+ if text is not None:
+ self.text = text
+
+ if html is not None:
+ self.html = html
+
+ @property
+ def enable(self):
+ """Indicates if this setting is enabled.
+
+ :rtype: boolean
+ """
+ return self._enable
+
+ @enable.setter
+ def enable(self, value):
+ """Indicates if this setting is enabled.
+
+ :param value: Indicates if this setting is enabled.
+ :type value: boolean
+ """
+ self._enable = value
+
+ @property
+ def text(self):
+ """The plain text content of your footer.
+
+ :rtype: string
+ """
+ return self._text
+
+ @text.setter
+ def text(self, value):
+ """The plain text content of your footer.
+
+ :param value: The plain text content of your footer.
+ :type value: string
+ """
+ self._text = value
+
+ @property
+ def html(self):
+ """The HTML content of your footer.
+
+ :rtype: string
+ """
+ return self._html
+
+ @html.setter
+ def html(self, value):
+ """The HTML content of your footer.
+
+ :param value: The HTML content of your footer.
+ :type value: string
+ """
+ self._html = value
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this FooterSettings.
+
+ :returns: This FooterSettings, ready for use in a request body.
+ :rtype: dict
+ """
+ footer_settings = {}
+ if self.enable is not None:
+ footer_settings["enable"] = self.enable
+
+ if self.text is not None:
+ footer_settings["text"] = self.text.get()
+
+ if self.html is not None:
+ footer_settings["html"] = self.html.get()
+ return footer_settings
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/footer_text.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/footer_text.py
new file mode 100644
index 00000000..06f96892
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/footer_text.py
@@ -0,0 +1,39 @@
+class FooterText(object):
+ """The text in an Footer."""
+
+ def __init__(self, footer_text=None):
+ """Create a FooterText object
+
+ :param footer_text: The plain text content of your footer.
+ :type footer_text: string, optional
+ """
+ self._footer_text = None
+
+ if footer_text is not None:
+ self.footer_text = footer_text
+
+ @property
+ def footer_text(self):
+ """The plain text content of your footer.
+
+ :rtype: string
+ """
+ return self._footer_text
+
+ @footer_text.setter
+ def footer_text(self, value):
+ """The plain text content of your footer.
+
+ :param value: The plain text content of your footer.
+ :type value: string
+ """
+ self._footer_text = value
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this FooterText.
+
+ :returns: This FooterText, ready for use in a request body.
+ :rtype: string
+ """
+ return self.footer_text
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/from_email.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/from_email.py
new file mode 100644
index 00000000..0f6f231c
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/from_email.py
@@ -0,0 +1,5 @@
+from .email import Email
+
+
+class From(Email):
+ """A from email address with an optional name."""
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/ganalytics.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/ganalytics.py
new file mode 100644
index 00000000..5f632715
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/ganalytics.py
@@ -0,0 +1,176 @@
+class Ganalytics(object):
+ """Allows you to enable tracking provided by Google Analytics."""
+
+ def __init__(self,
+ enable=None,
+ utm_source=None,
+ utm_medium=None,
+ utm_term=None,
+ utm_content=None,
+ utm_campaign=None):
+ """Create a GAnalytics to enable, customize Google Analytics tracking.
+
+ :param enable: If this setting is enabled.
+ :type enable: boolean, optional
+ :param utm_source: Name of the referrer source.
+ :type utm_source: string, optional
+ :param utm_medium: Name of the marketing medium (e.g. "Email").
+ :type utm_medium: string, optional
+ :param utm_term: Used to identify paid keywords.
+ :type utm_term: string, optional
+ :param utm_content: Used to differentiate your campaign from ads.
+ :type utm_content: string, optional
+ :param utm_campaign: The name of the campaign.
+ :type utm_campaign: string, optional
+ """
+ self._enable = None
+ self._utm_source = None
+ self._utm_medium = None
+ self._utm_term = None
+ self._utm_content = None
+ self._utm_campaign = None
+
+ self.__set_field("enable", enable)
+ self.__set_field("utm_source", utm_source)
+ self.__set_field("utm_medium", utm_medium)
+ self.__set_field("utm_term", utm_term)
+ self.__set_field("utm_content", utm_content)
+ self.__set_field("utm_campaign", utm_campaign)
+
+ def __set_field(self, field, value):
+ """ Sets a field to the provided value if value is not None
+
+ :param field: Name of the field
+ :type field: string
+ :param value: Value to be set, ignored if None
+ :type value: Any
+ """
+ if value is not None:
+ setattr(self, field, value)
+
+ @property
+ def enable(self):
+ """Indicates if this setting is enabled.
+
+ :rtype: boolean
+ """
+ return self._enable
+
+ @enable.setter
+ def enable(self, value):
+ """Indicates if this setting is enabled.
+
+ :param value: Indicates if this setting is enabled.
+ :type value: boolean
+ """
+ self._enable = value
+
+ @property
+ def utm_source(self):
+ """Name of the referrer source.
+ e.g. Google, SomeDomain.com, or Marketing Email
+
+ :rtype: string
+ """
+ return self._utm_source
+
+ @utm_source.setter
+ def utm_source(self, value):
+ """Name of the referrer source.
+ e.g. Google, SomeDomain.com, or Marketing Email
+
+ :param value: Name of the referrer source.
+ e.g. Google, SomeDomain.com, or Marketing Email
+ :type value: string
+ """
+ self._utm_source = value
+
+ @property
+ def utm_medium(self):
+ """Name of the marketing medium (e.g. Email).
+
+ :rtype: string
+ """
+ return self._utm_medium
+
+ @utm_medium.setter
+ def utm_medium(self, value):
+ """Name of the marketing medium (e.g. Email).
+
+ :param value: Name of the marketing medium (e.g. Email).
+ :type value: string
+ """
+ self._utm_medium = value
+
+ @property
+ def utm_term(self):
+ """Used to identify any paid keywords.
+
+ :rtype: string
+ """
+ return self._utm_term
+
+ @utm_term.setter
+ def utm_term(self, value):
+ """Used to identify any paid keywords.
+
+ :param value: Used to identify any paid keywords.
+ :type value: string
+ """
+ self._utm_term = value
+
+ @property
+ def utm_content(self):
+ """Used to differentiate your campaign from advertisements.
+
+ :rtype: string
+ """
+ return self._utm_content
+
+ @utm_content.setter
+ def utm_content(self, value):
+ """Used to differentiate your campaign from advertisements.
+
+ :param value: Used to differentiate your campaign from advertisements.
+ :type value: string
+ """
+ self._utm_content = value
+
+ @property
+ def utm_campaign(self):
+ """The name of the campaign.
+
+ :rtype: string
+ """
+ return self._utm_campaign
+
+ @utm_campaign.setter
+ def utm_campaign(self, value):
+ """The name of the campaign.
+
+ :param value: The name of the campaign.
+ :type value: string
+ """
+ self._utm_campaign = value
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this Ganalytics.
+
+ :returns: This Ganalytics, ready for use in a request body.
+ :rtype: dict
+ """
+ keys = ["enable", "utm_source", "utm_medium", "utm_term",
+ "utm_content", "utm_campaign"]
+
+ ganalytics = {}
+
+ for key in keys:
+ value = getattr(self, key, None)
+ if value is not None:
+ if isinstance(value, bool) or isinstance(value, str):
+ ganalytics[key] = value
+ else:
+ ganalytics[key] = value.get()
+
+ return ganalytics
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/group_id.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/group_id.py
new file mode 100644
index 00000000..66778531
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/group_id.py
@@ -0,0 +1,39 @@
+class GroupId(object):
+ """The unsubscribe group ID to associate with this email."""
+
+ def __init__(self, group_id=None):
+ """Create a GroupId object
+
+ :param group_id: The unsubscribe group to associate with this email.
+ :type group_id: integer, optional
+ """
+ self._group_id = None
+
+ if group_id is not None:
+ self.group_id = group_id
+
+ @property
+ def group_id(self):
+ """The unsubscribe group to associate with this email.
+
+ :rtype: integer
+ """
+ return self._group_id
+
+ @group_id.setter
+ def group_id(self, value):
+ """The unsubscribe group to associate with this email.
+
+ :param value: The unsubscribe group to associate with this email.
+ :type value: integer
+ """
+ self._group_id = value
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this GroupId.
+
+ :returns: This GroupId, ready for use in a request body.
+ :rtype: integer
+ """
+ return self.group_id
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/groups_to_display.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/groups_to_display.py
new file mode 100644
index 00000000..2e3fca77
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/groups_to_display.py
@@ -0,0 +1,48 @@
+class GroupsToDisplay(object):
+ """The unsubscribe groups that you would like to be displayed on the
+ unsubscribe preferences page.."""
+
+ def __init__(self, groups_to_display=None):
+ """Create a GroupsToDisplay object
+
+ :param groups_to_display: An array containing the unsubscribe groups
+ that you would like to be displayed on the
+ unsubscribe preferences page.
+ :type groups_to_display: array of integers, optional
+ """
+ self._groups_to_display = None
+
+ if groups_to_display is not None:
+ self.groups_to_display = groups_to_display
+
+ @property
+ def groups_to_display(self):
+ """An array containing the unsubscribe groups that you would like to be
+ displayed on the unsubscribe preferences page.
+
+ :rtype: array(int)
+ """
+ return self._groups_to_display
+
+ @groups_to_display.setter
+ def groups_to_display(self, value):
+ """An array containing the unsubscribe groups that you would like to be
+ displayed on the unsubscribe preferences page.
+
+ :param value: An array containing the unsubscribe groups that you
+ would like to be displayed on the unsubscribe
+ preferences page.
+ :type value: array(int)
+ """
+ if value is not None and len(value) > 25:
+ raise ValueError("New groups_to_display exceeds max length of 25.")
+ self._groups_to_display = value
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this GroupsToDisplay.
+
+ :returns: This GroupsToDisplay, ready for use in a request body.
+ :rtype: array of integers
+ """
+ return self.groups_to_display
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/header.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/header.py
new file mode 100644
index 00000000..7f3bd4c4
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/header.py
@@ -0,0 +1,94 @@
+class Header(object):
+ """A header to specify specific handling instructions for your email.
+
+ If the name or value contain Unicode characters, they must be properly
+ encoded. You may not overwrite the following reserved headers:
+ x-sg-id, x-sg-eid, received, dkim-signature, Content-Type,
+ Content-Transfer-Encoding, To, From, Subject, Reply-To, CC, BCC
+ """
+
+ def __init__(self, key=None, value=None, p=None):
+ """Create a Header.
+
+ :param key: The name of the header (e.g. "Date")
+ :type key: string, optional
+ :param value: The header's value (e.g. "2013-02-27 1:23:45 PM PDT")
+ :type value: string, optional
+ :param name: p is the Personalization object or Personalization object
+ index
+ :type name: Personalization, integer, optional
+ """
+ self._key = None
+ self._value = None
+ self._personalization = None
+
+ if key is not None:
+ self.key = key
+ if value is not None:
+ self.value = value
+ if p is not None:
+ self.personalization = p
+
+ @property
+ def key(self):
+ """The name of the header.
+
+ :rtype: string
+ """
+ return self._key
+
+ @key.setter
+ def key(self, value):
+ """The name of the header.
+
+ :param value: The name of the header.
+ :type value: string
+ """
+ self._key = value
+
+ @property
+ def value(self):
+ """The value of the header.
+
+ :rtype: string
+ """
+ return self._value
+
+ @value.setter
+ def value(self, value):
+ """The value of the header.
+
+ :param value: The value of the header.
+ :type value: string
+ """
+ self._value = value
+
+ @property
+ def personalization(self):
+ """The Personalization object or Personalization object index
+
+ :rtype: Personalization, integer
+ """
+ return self._personalization
+
+ @personalization.setter
+ def personalization(self, value):
+ """The Personalization object or Personalization object index
+
+ :param value: The Personalization object or Personalization object
+ index
+ :type value: Personalization, integer
+ """
+ self._personalization = value
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this Header.
+
+ :returns: This Header, ready for use in a request body.
+ :rtype: dict
+ """
+ header = {}
+ if self.key is not None and self.value is not None:
+ header[self.key] = self.value
+ return header
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/html_content.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/html_content.py
new file mode 100644
index 00000000..c3f40d53
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/html_content.py
@@ -0,0 +1,59 @@
+from .content import Content
+from .validators import ValidateApiKey
+
+
+class HtmlContent(Content):
+ """HTML content to be included in your email."""
+
+ def __init__(self, content):
+ """Create an HtmlContent with the specified MIME type and content.
+
+ :param content: The HTML content.
+ :type content: string
+ """
+ self._content = None
+ self._validator = ValidateApiKey()
+
+ if content is not None:
+ self.content = content
+
+ @property
+ def mime_type(self):
+ """The MIME type for HTML content.
+
+ :rtype: string
+ """
+ return "text/html"
+
+ @property
+ def content(self):
+ """The actual HTML content.
+
+ :rtype: string
+ """
+ return self._content
+
+ @content.setter
+ def content(self, value):
+ """The actual HTML content.
+
+ :param value: The actual HTML content.
+ :type value: string
+ """
+ self._validator.validate_message_dict(value)
+ self._content = value
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this HtmlContent.
+
+ :returns: This HtmlContent, ready for use in a request body.
+ :rtype: dict
+ """
+ content = {}
+ if self.mime_type is not None:
+ content["type"] = self.mime_type
+
+ if self.content is not None:
+ content["value"] = self.content
+ return content
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/ip_pool_name.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/ip_pool_name.py
new file mode 100644
index 00000000..8ba8d91b
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/ip_pool_name.py
@@ -0,0 +1,40 @@
+class IpPoolName(object):
+ """The IP Pool that you would like to send this email from."""
+
+ def __init__(self, ip_pool_name=None):
+ """Create a IpPoolName object
+
+ :param ip_pool_name: The IP Pool that you would like to send this
+ email from.
+ :type ip_pool_name: string, optional
+ """
+ self._ip_pool_name = None
+
+ if ip_pool_name is not None:
+ self.ip_pool_name = ip_pool_name
+
+ @property
+ def ip_pool_name(self):
+ """The IP Pool that you would like to send this email from.
+
+ :rtype: string
+ """
+ return self._ip_pool_name
+
+ @ip_pool_name.setter
+ def ip_pool_name(self, value):
+ """The IP Pool that you would like to send this email from.
+
+ :param value: The IP Pool that you would like to send this email from.
+ :type value: string
+ """
+ self._ip_pool_name = value
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this IpPoolName.
+
+ :returns: This IpPoolName, ready for use in a request body.
+ :rtype: string
+ """
+ return self.ip_pool_name
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/mail.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/mail.py
new file mode 100644
index 00000000..2472ad7d
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/mail.py
@@ -0,0 +1,1041 @@
+"""Twilio SendGrid v3/mail/send response body builder"""
+from .bcc_email import Bcc
+from .cc_email import Cc
+from .content import Content
+from .custom_arg import CustomArg
+from .dynamic_template_data import DynamicTemplateData
+from .email import Email
+from .from_email import From
+from .header import Header
+from .mime_type import MimeType
+from .personalization import Personalization
+from .reply_to import ReplyTo
+from .send_at import SendAt
+from .subject import Subject
+from .substitution import Substitution
+from .template_id import TemplateId
+from .to_email import To
+
+
+class Mail(object):
+ """Creates the response body for v3/mail/send"""
+
+ def __init__(
+ self,
+ from_email=None,
+ to_emails=None,
+ subject=None,
+ plain_text_content=None,
+ html_content=None,
+ amp_html_content=None,
+ global_substitutions=None,
+ is_multiple=False):
+ """
+ Creates the response body for a v3/mail/send API call
+
+ :param from_email: The email address of the sender
+ :type from_email: From, tuple, optional
+ :param subject: The subject of the email
+ :type subject: Subject, optional
+ :param to_emails: The email address of the recipient
+ :type to_emails: To, str, tuple, list(str), list(tuple),
+ list(To), optional
+ :param plain_text_content: The plain text body of the email
+ :type plain_text_content: string, optional
+ :param html_content: The html body of the email
+ :type html_content: string, optional
+ :param amp_html_content: The amp-html body of the email
+ :type amp_html_content: string, optional
+ """
+ self._attachments = None
+ self._categories = None
+ self._contents = None
+ self._custom_args = None
+ self._headers = None
+ self._personalizations = []
+ self._sections = None
+ self._asm = None
+ self._batch_id = None
+ self._from_email = None
+ self._ip_pool_name = None
+ self._mail_settings = None
+ self._reply_to = None
+ self._reply_to_list = None
+ self._send_at = None
+ self._subject = None
+ self._template_id = None
+ self._tracking_settings = None
+
+ # Minimum required data to send a single email
+ if from_email is not None:
+ self.from_email = from_email
+ if to_emails is not None:
+ self.add_to(to_emails, global_substitutions, is_multiple)
+ if subject is not None:
+ self.subject = subject
+ if plain_text_content is not None:
+ self.add_content(plain_text_content, MimeType.text)
+ if amp_html_content is not None:
+ self.add_content(amp_html_content, MimeType.amp)
+ if html_content is not None:
+ self.add_content(html_content, MimeType.html)
+
+ def __str__(self):
+ """A JSON-ready string representation of this Mail object.
+
+ :returns: A JSON-ready string representation of this Mail object.
+ :rtype: string
+ """
+ return str(self.get())
+
+ def _ensure_append(self, new_items, append_to, index=0):
+ """Ensure an item is appended to a list or create a new empty list
+
+ :param new_items: the item(s) to append
+ :type new_items: list(obj)
+ :param append_to: the list on which to append the items
+ :type append_to: list()
+ :param index: index of the list on which to append the items
+ :type index: int
+ """
+ append_to = append_to or []
+ append_to.insert(index, new_items)
+ return append_to
+
+ def _ensure_insert(self, new_items, insert_to):
+ """Ensure an item is inserted to a list or create a new empty list
+
+ :param new_items: the item(s) to insert
+ :type new_items: list(obj)
+ :param insert_to: the list on which to insert the items at index 0
+ :type insert_to: list()
+ """
+ insert_to = insert_to or []
+ insert_to.insert(0, new_items)
+ return insert_to
+
+ def _flatten_dicts(self, dicts):
+ """Flatten a dict
+
+ :param dicts: Flatten a dict
+ :type dicts: list(dict)
+ """
+ d = dict()
+ list_of_dicts = [d.get() for d in dicts or []]
+ return {k: v for d in list_of_dicts for k, v in d.items()}
+
+ def _get_or_none(self, from_obj):
+ """Get the JSON representation of the object, else return None
+
+ :param from_obj: Get the JSON representation of the object,
+ else return None
+ :type from_obj: obj
+ """
+ return from_obj.get() if from_obj is not None else None
+
+ def _set_emails(
+ self, emails, global_substitutions=None, is_multiple=False, p=0):
+ """Adds emails to the Personalization object
+
+ :param emails: An Email or list of Email objects
+ :type emails: Email, list(Email)
+ :param global_substitutions: A dict of substitutions for all recipients
+ :type global_substitutions: dict
+ :param is_multiple: Create a new personalization for each recipient
+ :type is_multiple: bool
+ :param p: p is the Personalization object or Personalization object
+ index
+ :type p: Personalization, integer, optional
+ """
+ # Send multiple emails to multiple recipients
+ if is_multiple is True:
+ if isinstance(emails, list):
+ for email in emails:
+ personalization = Personalization()
+ personalization.add_email(email)
+ self.add_personalization(personalization)
+ else:
+ personalization = Personalization()
+ personalization.add_email(emails)
+ self.add_personalization(personalization)
+ if global_substitutions is not None:
+ if isinstance(global_substitutions, list):
+ for substitution in global_substitutions:
+ for p in self.personalizations:
+ p.add_substitution(substitution)
+ else:
+ for p in self.personalizations:
+ p.add_substitution(global_substitutions)
+ else:
+ try:
+ personalization = self._personalizations[p]
+ has_internal_personalization = True
+ except IndexError:
+ personalization = Personalization()
+ has_internal_personalization = False
+
+ if isinstance(emails, list):
+ for email in emails:
+ personalization.add_email(email)
+ else:
+ personalization.add_email(emails)
+
+ if global_substitutions is not None:
+ if isinstance(global_substitutions, list):
+ for substitution in global_substitutions:
+ personalization.add_substitution(substitution)
+ else:
+ personalization.add_substitution(global_substitutions)
+
+ if not has_internal_personalization:
+ self.add_personalization(personalization, index=p)
+
+ @property
+ def personalizations(self):
+ """A list of one or more Personalization objects
+
+ :rtype: list(Personalization)
+ """
+ return self._personalizations
+
+ def add_personalization(self, personalization, index=0):
+ """Add a Personalization object
+
+ :param personalization: Add a Personalization object
+ :type personalization: Personalization
+ :param index: The index where to add the Personalization
+ :type index: int
+ """
+ self._personalizations = self._ensure_append(
+ personalization, self._personalizations, index)
+
+ @property
+ def to(self):
+ pass
+
+ @to.setter
+ def to(self, to_emails, global_substitutions=None, is_multiple=False, p=0):
+ """Adds To objects to the Personalization object
+
+ :param to_emails: The email addresses of all recipients
+ :type to_emails: To, str, tuple, list(str), list(tuple), list(To)
+ :param global_substitutions: A dict of substitutions for all recipients
+ :type global_substitutions: dict
+ :param is_multiple: Create a new personalization for each recipient
+ :type is_multiple: bool
+ :param p: p is the Personalization object or Personalization object
+ index
+ :type p: Personalization, integer, optional
+ """
+ if isinstance(to_emails, list):
+ for email in to_emails:
+ if isinstance(email, str):
+ email = To(email, None)
+ if isinstance(email, tuple):
+ email = To(email[0], email[1])
+ self.add_to(email, global_substitutions, is_multiple, p)
+ else:
+ if isinstance(to_emails, str):
+ to_emails = To(to_emails, None)
+ if isinstance(to_emails, tuple):
+ to_emails = To(to_emails[0], to_emails[1])
+ self.add_to(to_emails, global_substitutions, is_multiple, p)
+
+ def add_to(
+ self, to_email, global_substitutions=None, is_multiple=False, p=0):
+ """Adds a To object to the Personalization object
+
+ :param to_email: A To object
+ :type to_email: To, str, tuple, list(str), list(tuple), list(To)
+ :param global_substitutions: A dict of substitutions for all recipients
+ :type global_substitutions: dict
+ :param is_multiple: Create a new personalization for each recipient
+ :type is_multiple: bool
+ :param p: p is the Personalization object or Personalization object
+ index
+ :type p: Personalization, integer, optional
+ """
+
+ if isinstance(to_email, list):
+ for email in to_email:
+ if isinstance(email, str):
+ email = To(email, None)
+ elif isinstance(email, tuple):
+ email = To(email[0], email[1])
+ elif not isinstance(email, Email):
+ raise ValueError(
+ 'Please use a To/Cc/Bcc, tuple, or a str for a to_email list.'
+ )
+ self._set_emails(email, global_substitutions, is_multiple, p)
+ else:
+ if isinstance(to_email, str):
+ to_email = To(to_email, None)
+ if isinstance(to_email, tuple):
+ to_email = To(to_email[0], to_email[1])
+ if isinstance(to_email, Email):
+ p = to_email.personalization
+ self._set_emails(to_email, global_substitutions, is_multiple, p)
+
+ @property
+ def cc(self):
+ pass
+
+ @cc.setter
+ def cc(self, cc_emails, global_substitutions=None, is_multiple=False, p=0):
+ """Adds Cc objects to the Personalization object
+
+ :param cc_emails: An Cc or list of Cc objects
+ :type cc_emails: Cc, list(Cc), tuple
+ :param global_substitutions: A dict of substitutions for all recipients
+ :type global_substitutions: dict
+ :param is_multiple: Create a new personalization for each recipient
+ :type is_multiple: bool
+ :param p: p is the Personalization object or Personalization object
+ index
+ :type p: Personalization, integer, optional
+ """
+ if isinstance(cc_emails, list):
+ for email in cc_emails:
+ if isinstance(email, str):
+ email = Cc(email, None)
+ if isinstance(email, tuple):
+ email = Cc(email[0], email[1])
+ self.add_cc(email, global_substitutions, is_multiple, p)
+ else:
+ if isinstance(cc_emails, str):
+ cc_emails = Cc(cc_emails, None)
+ if isinstance(cc_emails, tuple):
+ cc_emails = To(cc_emails[0], cc_emails[1])
+ self.add_cc(cc_emails, global_substitutions, is_multiple, p)
+
+ def add_cc(
+ self, cc_email, global_substitutions=None, is_multiple=False, p=0):
+ """Adds a Cc object to the Personalization object
+
+ :param to_emails: An Cc object
+ :type to_emails: Cc
+ :param global_substitutions: A dict of substitutions for all recipients
+ :type global_substitutions: dict
+ :param is_multiple: Create a new personalization for each recipient
+ :type is_multiple: bool
+ :param p: p is the Personalization object or Personalization object
+ index
+ :type p: Personalization, integer, optional
+ """
+ if isinstance(cc_email, str):
+ cc_email = Cc(cc_email, None)
+ if isinstance(cc_email, tuple):
+ cc_email = Cc(cc_email[0], cc_email[1])
+ if isinstance(cc_email, Email):
+ p = cc_email.personalization
+ self._set_emails(
+ cc_email, global_substitutions, is_multiple=is_multiple, p=p)
+
+ @property
+ def bcc(self):
+ pass
+
+ @bcc.setter
+ def bcc(
+ self,
+ bcc_emails,
+ global_substitutions=None,
+ is_multiple=False,
+ p=0):
+ """Adds Bcc objects to the Personalization object
+
+ :param bcc_emails: An Bcc or list of Bcc objects
+ :type bcc_emails: Bcc, list(Bcc), tuple
+ :param global_substitutions: A dict of substitutions for all recipients
+ :type global_substitutions: dict
+ :param is_multiple: Create a new personalization for each recipient
+ :type is_multiple: bool
+ :param p: p is the Personalization object or Personalization object
+ index
+ :type p: Personalization, integer, optional
+ """
+ if isinstance(bcc_emails, list):
+ for email in bcc_emails:
+ if isinstance(email, str):
+ email = Bcc(email, None)
+ if isinstance(email, tuple):
+ email = Bcc(email[0], email[1])
+ self.add_bcc(email, global_substitutions, is_multiple, p)
+ else:
+ if isinstance(bcc_emails, str):
+ bcc_emails = Bcc(bcc_emails, None)
+ if isinstance(bcc_emails, tuple):
+ bcc_emails = Bcc(bcc_emails[0], bcc_emails[1])
+ self.add_bcc(bcc_emails, global_substitutions, is_multiple, p)
+
+ def add_bcc(
+ self,
+ bcc_email,
+ global_substitutions=None,
+ is_multiple=False,
+ p=0):
+ """Adds a Bcc object to the Personalization object
+
+ :param to_emails: An Bcc object
+ :type to_emails: Bcc
+ :param global_substitutions: A dict of substitutions for all recipients
+ :type global_substitutions: dict
+ :param is_multiple: Create a new personalization for each recipient
+ :type is_multiple: bool
+ :param p: p is the Personalization object or Personalization object
+ index
+ :type p: Personalization, integer, optional
+ """
+ if isinstance(bcc_email, str):
+ bcc_email = Bcc(bcc_email, None)
+ if isinstance(bcc_email, tuple):
+ bcc_email = Bcc(bcc_email[0], bcc_email[1])
+ if isinstance(bcc_email, Email):
+ p = bcc_email.personalization
+ self._set_emails(
+ bcc_email,
+ global_substitutions,
+ is_multiple=is_multiple,
+ p=p)
+
+ @property
+ def subject(self):
+ """The global Subject object
+
+ :rtype: Subject
+ """
+ return self._subject
+
+ @subject.setter
+ def subject(self, value):
+ """The subject of the email(s)
+
+ :param value: The subject of the email(s)
+ :type value: Subject, string
+ """
+ if isinstance(value, Subject):
+ if value.personalization is not None:
+ try:
+ personalization = \
+ self._personalizations[value.personalization]
+ has_internal_personalization = True
+ except IndexError:
+ personalization = Personalization()
+ has_internal_personalization = False
+ personalization.subject = value.subject
+
+ if not has_internal_personalization:
+ self.add_personalization(
+ personalization,
+ index=value.personalization)
+ else:
+ self._subject = value
+ else:
+ self._subject = Subject(value)
+
+ @property
+ def headers(self):
+ """A list of global Header objects
+
+ :rtype: list(Header)
+ """
+ return self._headers
+
+ @property
+ def header(self):
+ pass
+
+ @header.setter
+ def header(self, headers):
+ """Add headers to the email
+
+ :param value: A list of Header objects or a dict of header key/values
+ :type value: Header, list(Header), dict
+ """
+ if isinstance(headers, list):
+ for h in headers:
+ self.add_header(h)
+ else:
+ self.add_header(headers)
+
+ def add_header(self, header):
+ """Add headers to the email globaly or to a specific Personalization
+
+ :param value: A Header object or a dict of header key/values
+ :type value: Header, dict
+ """
+ if header.personalization is not None:
+ try:
+ personalization = \
+ self._personalizations[header.personalization]
+ has_internal_personalization = True
+ except IndexError:
+ personalization = Personalization()
+ has_internal_personalization = False
+ if isinstance(header, dict):
+ (k, v) = list(header.items())[0]
+ personalization.add_header(Header(k, v))
+ else:
+ personalization.add_header(header)
+
+ if not has_internal_personalization:
+ self.add_personalization(
+ personalization,
+ index=header.personalization)
+ else:
+ if isinstance(header, dict):
+ (k, v) = list(header.items())[0]
+ self._headers = self._ensure_append(
+ Header(k, v), self._headers)
+ else:
+ self._headers = self._ensure_append(header, self._headers)
+
+ @property
+ def substitution(self):
+ pass
+
+ @substitution.setter
+ def substitution(self, substitution):
+ """Add substitutions to the email
+
+ :param value: Add substitutions to the email
+ :type value: Substitution, list(Substitution)
+ """
+ if isinstance(substitution, list):
+ for s in substitution:
+ self.add_substitution(s)
+ else:
+ self.add_substitution(substitution)
+
+ def add_substitution(self, substitution):
+ """Add a substitution to the email
+
+ :param value: Add a substitution to the email
+ :type value: Substitution
+ """
+ if substitution.personalization:
+ try:
+ personalization = \
+ self._personalizations[substitution.personalization]
+ has_internal_personalization = True
+ except IndexError:
+ personalization = Personalization()
+ has_internal_personalization = False
+ personalization.add_substitution(substitution)
+
+ if not has_internal_personalization:
+ self.add_personalization(
+ personalization, index=substitution.personalization)
+ else:
+ if isinstance(substitution, list):
+ for s in substitution:
+ for p in self.personalizations:
+ p.add_substitution(s)
+ else:
+ for p in self.personalizations:
+ p.add_substitution(substitution)
+
+ @property
+ def custom_args(self):
+ """A list of global CustomArg objects
+
+ :rtype: list(CustomArg)
+ """
+ return self._custom_args
+
+ @property
+ def custom_arg(self):
+ return self._custom_args
+
+ @custom_arg.setter
+ def custom_arg(self, custom_arg):
+ """Add custom args to the email
+
+ :param value: A list of CustomArg objects or a dict of custom arg
+ key/values
+ :type value: CustomArg, list(CustomArg), dict
+ """
+ if isinstance(custom_arg, list):
+ for c in custom_arg:
+ self.add_custom_arg(c)
+ else:
+ self.add_custom_arg(custom_arg)
+
+ def add_custom_arg(self, custom_arg):
+ """Add custom args to the email globaly or to a specific Personalization
+
+ :param value: A CustomArg object or a dict of custom arg key/values
+ :type value: CustomArg, dict
+ """
+ if custom_arg.personalization is not None:
+ try:
+ personalization = \
+ self._personalizations[custom_arg.personalization]
+ has_internal_personalization = True
+ except IndexError:
+ personalization = Personalization()
+ has_internal_personalization = False
+ if isinstance(custom_arg, dict):
+ (k, v) = list(custom_arg.items())[0]
+ personalization.add_custom_arg(CustomArg(k, v))
+ else:
+ personalization.add_custom_arg(custom_arg)
+
+ if not has_internal_personalization:
+ self.add_personalization(
+ personalization, index=custom_arg.personalization)
+ else:
+ if isinstance(custom_arg, dict):
+ (k, v) = list(custom_arg.items())[0]
+ self._custom_args = self._ensure_append(
+ CustomArg(k, v), self._custom_args)
+ else:
+ self._custom_args = self._ensure_append(
+ custom_arg, self._custom_args)
+
+ @property
+ def send_at(self):
+ """The global SendAt object
+
+ :rtype: SendAt
+ """
+ return self._send_at
+
+ @send_at.setter
+ def send_at(self, value):
+ """A unix timestamp specifying when your email should
+ be delivered.
+
+ :param value: A unix timestamp specifying when your email should
+ be delivered.
+ :type value: SendAt, int
+ """
+ if isinstance(value, SendAt):
+ if value.personalization is not None:
+ try:
+ personalization = \
+ self._personalizations[value.personalization]
+ has_internal_personalization = True
+ except IndexError:
+ personalization = Personalization()
+ has_internal_personalization = False
+ personalization.send_at = value.send_at
+
+ if not has_internal_personalization:
+ self.add_personalization(
+ personalization, index=value.personalization)
+ else:
+ self._send_at = value
+ else:
+ self._send_at = SendAt(value)
+
+ @property
+ def dynamic_template_data(self):
+ pass
+
+ @dynamic_template_data.setter
+ def dynamic_template_data(self, value):
+ """Data for a transactional template
+
+ :param value: Data for a transactional template
+ :type value: DynamicTemplateData, a JSON-serializable structure
+ """
+ if not isinstance(value, DynamicTemplateData):
+ value = DynamicTemplateData(value)
+ try:
+ personalization = self._personalizations[value.personalization]
+ has_internal_personalization = True
+ except IndexError:
+ personalization = Personalization()
+ has_internal_personalization = False
+ personalization.dynamic_template_data = value.dynamic_template_data
+
+ if not has_internal_personalization:
+ self.add_personalization(
+ personalization, index=value.personalization)
+
+ @property
+ def from_email(self):
+ """The email address of the sender
+
+ :rtype: From
+ """
+ return self._from_email
+
+ @from_email.setter
+ def from_email(self, value):
+ """The email address of the sender
+
+ :param value: The email address of the sender
+ :type value: From, str, tuple
+ """
+ if isinstance(value, str):
+ value = From(value, None)
+ if isinstance(value, tuple):
+ value = From(value[0], value[1])
+ self._from_email = value
+
+ @property
+ def reply_to(self):
+ """The reply to email address
+
+ :rtype: ReplyTo
+ """
+ return self._reply_to
+
+ @reply_to.setter
+ def reply_to(self, value):
+ """The reply to email address
+
+ :param value: The reply to email address
+ :type value: ReplyTo, str, tuple
+ """
+ if isinstance(value, str):
+ value = ReplyTo(value, None)
+ if isinstance(value, tuple):
+ value = ReplyTo(value[0], value[1])
+ self._reply_to = value
+
+ @property
+ def reply_to_list(self):
+ """A list of ReplyTo email addresses
+
+ :rtype: list(ReplyTo), tuple
+ """
+ return self._reply_to_list
+
+ @reply_to_list.setter
+ def reply_to_list(self, value):
+ """A list of ReplyTo email addresses
+
+ :param value: A list of ReplyTo email addresses
+ :type value: list(ReplyTo), tuple
+ """
+ if isinstance(value, list):
+ for reply in value:
+ if isinstance(reply, ReplyTo):
+ if not isinstance(reply.email, str):
+ raise ValueError('You must provide an email for each entry in a reply_to_list')
+ else:
+ raise ValueError(
+ 'Please use a list of ReplyTos for a reply_to_list.'
+ )
+ self._reply_to_list = value
+
+ @property
+ def contents(self):
+ """The contents of the email
+
+ :rtype: list(Content)
+ """
+ return self._contents
+
+ @property
+ def content(self):
+ pass
+
+ @content.setter
+ def content(self, contents):
+ """The content(s) of the email
+
+ :param contents: The content(s) of the email
+ :type contents: Content, list(Content)
+ """
+ if isinstance(contents, list):
+ for c in contents:
+ self.add_content(c)
+ else:
+ self.add_content(contents)
+
+ def add_content(self, content, mime_type=None):
+ """Add content to the email
+
+ :param contents: Content to be added to the email
+ :type contents: Content
+ :param mime_type: Override the mime type
+ :type mime_type: MimeType, str
+ """
+ if isinstance(content, str):
+ content = Content(mime_type, content)
+ # Content of mime type text/plain must always come first, followed by text/x-amp-html and then text/html
+ if content.mime_type == MimeType.text:
+ self._contents = self._ensure_insert(content, self._contents)
+ elif content.mime_type == MimeType.amp:
+ if self._contents:
+ for _content in self._contents:
+ # this is written in the context that plain text content will always come earlier than the html content
+ if _content.mime_type == MimeType.text:
+ index = 1
+ break
+ elif _content.mime_type == MimeType.html:
+ index = 0
+ break
+ else:
+ index = 0
+ self._contents = self._ensure_append(
+ content, self._contents, index=index)
+ else:
+ if self._contents:
+ index = len(self._contents)
+ else:
+ index = 0
+ self._contents = self._ensure_append(
+ content, self._contents, index=index)
+
+ @property
+ def attachments(self):
+ """The attachments to this email
+
+ :rtype: list(Attachment)
+ """
+ return self._attachments
+
+ @property
+ def attachment(self):
+ pass
+
+ @attachment.setter
+ def attachment(self, attachment):
+ """Add attachment(s) to this email
+
+ :param attachment: Add attachment(s) to this email
+ :type attachment: Attachment, list(Attachment)
+ """
+ if isinstance(attachment, list):
+ for a in attachment:
+ self.add_attachment(a)
+ else:
+ self.add_attachment(attachment)
+
+ def add_attachment(self, attachment):
+ """Add an attachment to this email
+
+ :param attachment: Add an attachment to this email
+ :type attachment: Attachment
+ """
+ self._attachments = self._ensure_append(attachment, self._attachments)
+
+ @property
+ def template_id(self):
+ """The transactional template id for this email
+
+ :rtype: TemplateId
+ """
+ return self._template_id
+
+ @template_id.setter
+ def template_id(self, value):
+ """The transactional template id for this email
+
+ :param value: The transactional template id for this email
+ :type value: TemplateId
+ """
+ if isinstance(value, TemplateId):
+ self._template_id = value
+ else:
+ self._template_id = TemplateId(value)
+
+ @property
+ def sections(self):
+ """The block sections of code to be used as substitutions
+
+ :rtype: Section
+ """
+ return self._sections
+
+ @property
+ def section(self):
+ pass
+
+ @section.setter
+ def section(self, section):
+ """The block sections of code to be used as substitutions
+
+ :rtype: Section, list(Section)
+ """
+ if isinstance(section, list):
+ for h in section:
+ self.add_section(h)
+ else:
+ self.add_section(section)
+
+ def add_section(self, section):
+ """A block section of code to be used as substitutions
+
+ :param section: A block section of code to be used as substitutions
+ :type section: Section
+ """
+ self._sections = self._ensure_append(section, self._sections)
+
+ @property
+ def categories(self):
+ """The categories assigned to this message
+
+ :rtype: list(Category)
+ """
+ return self._categories
+
+ @property
+ def category(self):
+ pass
+
+ @category.setter
+ def category(self, categories):
+ """Add categories assigned to this message
+
+ :rtype: list(Category)
+ """
+ if isinstance(categories, list):
+ for c in categories:
+ self.add_category(c)
+ else:
+ self.add_category(categories)
+
+ def add_category(self, category):
+ """Add a category assigned to this message
+
+ :rtype: Category
+ """
+ self._categories = self._ensure_append(category, self._categories)
+
+ @property
+ def batch_id(self):
+ """The batch id for this email
+
+ :rtype: BatchId
+ """
+ return self._batch_id
+
+ @batch_id.setter
+ def batch_id(self, value):
+ """The batch id for this email
+
+ :param value: The batch id for this email
+ :type value: BatchId
+ """
+ self._batch_id = value
+
+ @property
+ def asm(self):
+ """An object specifying unsubscribe behavior.
+
+ :rtype: Asm
+ """
+ return self._asm
+
+ @asm.setter
+ def asm(self, value):
+ """An object specifying unsubscribe behavior.
+
+ :param value: An object specifying unsubscribe behavior.
+ :type value: Asm
+ """
+ self._asm = value
+
+ @property
+ def ip_pool_name(self):
+ """The IP Pool that you would like to send this email from
+
+ :rtype: IpPoolName
+ """
+ return self._ip_pool_name
+
+ @ip_pool_name.setter
+ def ip_pool_name(self, value):
+ """The IP Pool that you would like to send this email from
+
+ :paran value: The IP Pool that you would like to send this email from
+ :type value: IpPoolName
+ """
+ self._ip_pool_name = value
+
+ @property
+ def mail_settings(self):
+ """The mail settings for this email
+
+ :rtype: MailSettings
+ """
+ return self._mail_settings
+
+ @mail_settings.setter
+ def mail_settings(self, value):
+ """The mail settings for this email
+
+ :param value: The mail settings for this email
+ :type value: MailSettings
+ """
+ self._mail_settings = value
+
+ @property
+ def tracking_settings(self):
+ """The tracking settings for this email
+
+ :rtype: TrackingSettings
+ """
+ return self._tracking_settings
+
+ @tracking_settings.setter
+ def tracking_settings(self, value):
+ """The tracking settings for this email
+
+ :param value: The tracking settings for this email
+ :type value: TrackingSettings
+ """
+ self._tracking_settings = value
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this Mail object.
+
+ :returns: This Mail object, ready for use in a request body.
+ :rtype: dict
+ """
+ mail = {
+ 'from': self._get_or_none(self.from_email),
+ 'subject': self._get_or_none(self.subject),
+ 'personalizations': [p.get() for p in self.personalizations or []],
+ 'content': [c.get() for c in self.contents or []],
+ 'attachments': [a.get() for a in self.attachments or []],
+ 'template_id': self._get_or_none(self.template_id),
+ 'sections': self._flatten_dicts(self.sections),
+ 'headers': self._flatten_dicts(self.headers),
+ 'categories': [c.get() for c in self.categories or []],
+ 'custom_args': self._flatten_dicts(self.custom_args),
+ 'send_at': self._get_or_none(self.send_at),
+ 'batch_id': self._get_or_none(self.batch_id),
+ 'asm': self._get_or_none(self.asm),
+ 'ip_pool_name': self._get_or_none(self.ip_pool_name),
+ 'mail_settings': self._get_or_none(self.mail_settings),
+ 'tracking_settings': self._get_or_none(self.tracking_settings),
+ 'reply_to': self._get_or_none(self.reply_to),
+ 'reply_to_list': [r.get() for r in self.reply_to_list or []],
+ }
+
+ return {key: value for key, value in mail.items()
+ if value is not None and value != [] and value != {}}
+
+ @classmethod
+ def from_EmailMessage(cls, message):
+ """Create a Mail object from an instance of
+ email.message.EmailMessage.
+
+ :type message: email.message.EmailMessage
+ :rtype: Mail
+ """
+ mail = cls(
+ from_email=Email(message.get('From')),
+ subject=message.get('Subject'),
+ to_emails=Email(message.get('To')),
+ )
+ try:
+ body = message.get_content()
+ except AttributeError:
+ # Python2
+ body = message.get_payload()
+ mail.add_content(Content(
+ message.get_content_type(),
+ body.strip()
+ ))
+ for k, v in message.items():
+ mail.add_header(Header(k, v))
+ return mail
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/mail_settings.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/mail_settings.py
new file mode 100644
index 00000000..78499ac3
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/mail_settings.py
@@ -0,0 +1,243 @@
+class MailSettings(object):
+ """A collection of mail settings that specify how to handle this email."""
+
+ def __init__(self,
+ bcc_settings=None,
+ bypass_bounce_management=None,
+ bypass_list_management=None,
+ bypass_spam_management=None,
+ bypass_unsubscribe_management=None,
+ footer_settings=None,
+ sandbox_mode=None,
+ spam_check=None):
+ """Create a MailSettings object
+
+ :param bcc_settings: The BCC Settings of this MailSettings
+ :type bcc_settings: BCCSettings, optional
+ :param bypass_bounce_management: Whether this MailSettings bypasses bounce management.
+ Should not be combined with bypass_list_management.
+ :type bypass_list_management: BypassBounceManagement, optional
+ :param bypass_list_management: Whether this MailSettings bypasses list
+ management
+ :type bypass_list_management: BypassListManagement, optional
+ :param bypass_spam_management: Whether this MailSettings bypasses spam management.
+ Should not be combined with bypass_list_management.
+ :type bypass_list_management: BypassSpamManagement, optional
+ :param bypass_unsubscribe_management: Whether this MailSettings bypasses unsubscribe management.
+ Should not be combined with bypass_list_management.
+ :type bypass_list_management: BypassUnsubscribeManagement, optional
+ :param footer_settings: The default footer specified by this
+ MailSettings
+ :type footer_settings: FooterSettings, optional
+ :param sandbox_mode: Whether this MailSettings enables sandbox mode
+ :type sandbox_mode: SandBoxMode, optional
+ :param spam_check: How this MailSettings requests email to be checked
+ for spam
+ :type spam_check: SpamCheck, optional
+ """
+ self._bcc_settings = None
+ self._bypass_bounce_management = None
+ self._bypass_list_management = None
+ self._bypass_spam_management = None
+ self._bypass_unsubscribe_management = None
+ self._footer_settings = None
+ self._sandbox_mode = None
+ self._spam_check = None
+
+ if bcc_settings is not None:
+ self.bcc_settings = bcc_settings
+
+ if bypass_bounce_management is not None:
+ self.bypass_bounce_management = bypass_bounce_management
+
+ if bypass_list_management is not None:
+ self.bypass_list_management = bypass_list_management
+
+ if bypass_spam_management is not None:
+ self.bypass_spam_management = bypass_spam_management
+
+ if bypass_unsubscribe_management is not None:
+ self.bypass_unsubscribe_management = bypass_unsubscribe_management
+
+ if footer_settings is not None:
+ self.footer_settings = footer_settings
+
+ if sandbox_mode is not None:
+ self.sandbox_mode = sandbox_mode
+
+ if spam_check is not None:
+ self.spam_check = spam_check
+
+ @property
+ def bcc_settings(self):
+ """The BCC Settings of this MailSettings.
+
+ :rtype: BCCSettings
+ """
+ return self._bcc_settings
+
+ @bcc_settings.setter
+ def bcc_settings(self, value):
+ """The BCC Settings of this MailSettings.
+
+ :param value: The BCC Settings of this MailSettings.
+ :type value: BCCSettings
+ """
+ self._bcc_settings = value
+
+ @property
+ def bypass_bounce_management(self):
+ """Whether this MailSettings bypasses bounce management.
+
+ :rtype: BypassBounceManagement
+ """
+ return self._bypass_bounce_management
+
+ @bypass_bounce_management.setter
+ def bypass_bounce_management(self, value):
+ """Whether this MailSettings bypasses bounce management.
+
+ :param value: Whether this MailSettings bypasses bounce management.
+ :type value: BypassBounceManagement
+ """
+ self._bypass_bounce_management = value
+
+ @property
+ def bypass_list_management(self):
+ """Whether this MailSettings bypasses list management.
+
+ :rtype: BypassListManagement
+ """
+ return self._bypass_list_management
+
+ @bypass_list_management.setter
+ def bypass_list_management(self, value):
+ """Whether this MailSettings bypasses list management.
+
+ :param value: Whether this MailSettings bypasses list management.
+ :type value: BypassListManagement
+ """
+ self._bypass_list_management = value
+
+ @property
+ def bypass_spam_management(self):
+ """Whether this MailSettings bypasses spam management.
+
+ :rtype: BypassSpamManagement
+ """
+ return self._bypass_spam_management
+
+ @bypass_spam_management.setter
+ def bypass_spam_management(self, value):
+ """Whether this MailSettings bypasses spam management.
+
+ :param value: Whether this MailSettings bypasses spam management.
+ :type value: BypassSpamManagement
+ """
+ self._bypass_spam_management = value
+
+ @property
+ def bypass_unsubscribe_management(self):
+ """Whether this MailSettings bypasses unsubscribe management.
+
+ :rtype: BypassUnsubscribeManagement
+ """
+ return self._bypass_unsubscribe_management
+
+ @bypass_unsubscribe_management.setter
+ def bypass_unsubscribe_management(self, value):
+ """Whether this MailSettings bypasses unsubscribe management.
+
+ :param value: Whether this MailSettings bypasses unsubscribe management.
+ :type value: BypassUnsubscribeManagement
+ """
+ self._bypass_unsubscribe_management = value
+
+ @property
+ def footer_settings(self):
+ """The default footer specified by this MailSettings.
+
+ :rtype: FooterSettings
+ """
+ return self._footer_settings
+
+ @footer_settings.setter
+ def footer_settings(self, value):
+ """The default footer specified by this MailSettings.
+
+ :param value: The default footer specified by this MailSettings.
+ :type value: FooterSettings
+ """
+ self._footer_settings = value
+
+ @property
+ def sandbox_mode(self):
+ """Whether this MailSettings enables sandbox mode.
+
+ :rtype: SandBoxMode
+ """
+ return self._sandbox_mode
+
+ @sandbox_mode.setter
+ def sandbox_mode(self, value):
+ """Whether this MailSettings enables sandbox mode.
+
+ :param value: Whether this MailSettings enables sandbox mode.
+ :type value: SandBoxMode
+ """
+ self._sandbox_mode = value
+
+ @property
+ def spam_check(self):
+ """How this MailSettings requests email to be checked for spam.
+
+ :rtype: SpamCheck
+ """
+ return self._spam_check
+
+ @spam_check.setter
+ def spam_check(self, value):
+ """How this MailSettings requests email to be checked for spam.
+
+ :param value: How this MailSettings requests email to be checked
+ for spam.
+ :type value: SpamCheck
+ """
+ self._spam_check = value
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this MailSettings.
+
+ :returns: This MailSettings, ready for use in a request body.
+ :rtype: dict
+ """
+ mail_settings = {}
+ if self.bcc_settings is not None:
+ mail_settings["bcc"] = self.bcc_settings.get()
+
+ if self.bypass_bounce_management is not None:
+ mail_settings[
+ "bypass_bounce_management"] = self.bypass_bounce_management.get()
+
+ if self.bypass_list_management is not None:
+ mail_settings[
+ "bypass_list_management"] = self.bypass_list_management.get()
+
+ if self.bypass_spam_management is not None:
+ mail_settings[
+ "bypass_spam_management"] = self.bypass_spam_management.get()
+
+ if self.bypass_unsubscribe_management is not None:
+ mail_settings[
+ "bypass_unsubscribe_management"] = self.bypass_unsubscribe_management.get()
+
+ if self.footer_settings is not None:
+ mail_settings["footer"] = self.footer_settings.get()
+
+ if self.sandbox_mode is not None:
+ mail_settings["sandbox_mode"] = self.sandbox_mode.get()
+
+ if self.spam_check is not None:
+ mail_settings["spam_check"] = self.spam_check.get()
+ return mail_settings
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/mime_type.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/mime_type.py
new file mode 100644
index 00000000..a2f88c5a
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/mime_type.py
@@ -0,0 +1,6 @@
+class MimeType(object):
+ """The MIME type of the content included in your email.
+ """
+ text = "text/plain"
+ html = "text/html"
+ amp = "text/x-amp-html"
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/open_tracking.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/open_tracking.py
new file mode 100644
index 00000000..7124a2e6
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/open_tracking.py
@@ -0,0 +1,80 @@
+class OpenTracking(object):
+ """
+ Allows you to track whether the email was opened or not, by including a
+ single pixel image in the body of the content. When the pixel is loaded,
+ we log that the email was opened.
+ """
+
+ def __init__(self, enable=None, substitution_tag=None):
+ """Create an OpenTracking to track when your email is opened.
+
+ :param enable: If open tracking is enabled.
+ :type enable: boolean, optional
+ :param substitution_tag: Tag in body to be replaced by tracking pixel.
+ :type substitution_tag: OpenTrackingSubstitionTag, optional
+ """
+ self._enable = None
+ self._substitution_tag = None
+
+ if enable is not None:
+ self.enable = enable
+
+ if substitution_tag is not None:
+ self.substitution_tag = substitution_tag
+
+ @property
+ def enable(self):
+ """Indicates if this setting is enabled.
+
+ :rtype: boolean
+ """
+ return self._enable
+
+ @enable.setter
+ def enable(self, value):
+ """Indicates if this setting is enabled.
+
+ :param value: Indicates if this setting is enabled.
+ :type value: boolean
+ """
+ self._enable = value
+
+ @property
+ def substitution_tag(self):
+ """Allows you to specify a substitution tag that you can insert in the
+ body of your email at a location that you desire. This tag will be
+ replaced by the open tracking pixel.
+
+ :rtype: string
+ """
+ return self._substitution_tag
+
+ @substitution_tag.setter
+ def substitution_tag(self, value):
+ """Allows you to specify a substitution tag that you can insert in the
+ body of your email at a location that you desire. This tag will be
+ replaced by the open tracking pixel.
+
+ :param value: Allows you to specify a substitution tag that you can
+ insert in the body of your email at a location that you
+ desire. This tag will be replaced by the open tracking
+ pixel.
+
+ :type value: string
+ """
+ self._substitution_tag = value
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this OpenTracking.
+
+ :returns: This OpenTracking, ready for use in a request body.
+ :rtype: dict
+ """
+ open_tracking = {}
+ if self.enable is not None:
+ open_tracking["enable"] = self.enable
+
+ if self.substitution_tag is not None:
+ open_tracking["substitution_tag"] = self.substitution_tag.get()
+ return open_tracking
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/open_tracking_substitution_tag.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/open_tracking_substitution_tag.py
new file mode 100644
index 00000000..d9967f9c
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/open_tracking_substitution_tag.py
@@ -0,0 +1,49 @@
+class OpenTrackingSubstitutionTag(object):
+ """The open tracking substitution tag of an SubscriptionTracking object."""
+
+ def __init__(self, open_tracking_substitution_tag=None):
+ """Create a OpenTrackingSubstitutionTag object
+
+ :param open_tracking_substitution_tag: Allows you to specify a
+ substitution tag that you can insert in the body of your
+ email at a location that you desire. This tag will be replaced
+ by the open tracking pixel.
+ """
+ self._open_tracking_substitution_tag = None
+
+ if open_tracking_substitution_tag is not None:
+ self.open_tracking_substitution_tag = \
+ open_tracking_substitution_tag
+
+ @property
+ def open_tracking_substitution_tag(self):
+ """Allows you to specify a substitution tag that you can insert in
+ the body of your email at a location that you desire. This tag
+ will be replaced by the open tracking pixel.
+
+ :rtype: string
+ """
+ return self._open_tracking_substitution_tag
+
+ @open_tracking_substitution_tag.setter
+ def open_tracking_substitution_tag(self, value):
+ """Allows you to specify a substitution tag that you can insert in
+ the body of your email at a location that you desire. This tag will
+ be replaced by the open tracking pixel.
+
+ :param value: Allows you to specify a substitution tag that you can
+ insert in the body of your email at a location that you desire. This
+ tag will be replaced by the open tracking pixel.
+ :type value: string
+ """
+ self._open_tracking_substitution_tag = value
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this OpenTrackingSubstitutionTag.
+
+ :returns: This OpenTrackingSubstitutionTag, ready for use in a request
+ body.
+ :rtype: string
+ """
+ return self.open_tracking_substitution_tag
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/personalization.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/personalization.py
new file mode 100644
index 00000000..a4e1c1de
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/personalization.py
@@ -0,0 +1,271 @@
+class Personalization(object):
+ """A Personalization defines who should receive an individual message and
+ how that message should be handled.
+ """
+
+ def __init__(self):
+ """Create an empty Personalization and initialize member variables."""
+ self._tos = []
+ self._from_email = None
+ self._ccs = []
+ self._bccs = []
+ self._subject = None
+ self._headers = []
+ self._substitutions = []
+ self._custom_args = []
+ self._send_at = None
+ self._dynamic_template_data = None
+
+ def add_email(self, email):
+ email_type = type(email)
+ if email_type.__name__ == 'To':
+ self.add_to(email)
+ return
+ if email_type.__name__ == 'Cc':
+ self.add_cc(email)
+ return
+ if email_type.__name__ == 'Bcc':
+ self.add_bcc(email)
+ return
+ if email_type.__name__ == 'From':
+ self.from_email = email
+ return
+ raise ValueError('Please use a To, From, Cc or Bcc object.')
+
+ def _get_unique_recipients(self, recipients):
+ unique_recipients = []
+
+ for recipient in recipients:
+ recipient_email = recipient['email'].lower() if isinstance(recipient, dict) else recipient.email.lower()
+ if all(
+ unique_recipient['email'].lower() != recipient_email for unique_recipient in unique_recipients
+ ):
+ new_unique_recipient = recipient if isinstance(recipient, dict) else recipient.get()
+ unique_recipients.append(new_unique_recipient)
+
+ return unique_recipients
+
+
+ @property
+ def tos(self):
+ """A list of recipients for this Personalization.
+
+ :rtype: list(dict)
+ """
+ return self._get_unique_recipients(self._tos)
+
+ @tos.setter
+ def tos(self, value):
+ self._tos = value
+
+ def add_to(self, email):
+ """Add a single recipient to this Personalization.
+
+ :type email: Email
+ """
+ if email.substitutions:
+ if isinstance(email.substitutions, list):
+ for substitution in email.substitutions:
+ self.add_substitution(substitution)
+ else:
+ self.add_substitution(email.substitutions)
+
+ if email.dynamic_template_data:
+ self.dynamic_template_data = email.dynamic_template_data
+
+ if email.subject:
+ if isinstance(email.subject, str):
+ self.subject = email.subject
+ else:
+ self.subject = email.subject.get()
+
+ self._tos.append(email.get())
+
+ @property
+ def from_email(self):
+ return self._from_email
+
+ @from_email.setter
+ def from_email(self, value):
+ self._from_email = value
+
+ def set_from(self, email):
+ self._from_email = email.get()
+
+ @property
+ def ccs(self):
+ """A list of recipients who will receive copies of this email.
+
+ :rtype: list(dict)
+ """
+ return self._get_unique_recipients(self._ccs)
+
+ @ccs.setter
+ def ccs(self, value):
+ self._ccs = value
+
+ def add_cc(self, email):
+ """Add a single recipient to receive a copy of this email.
+
+ :param email: new recipient to be CCed
+ :type email: Email
+ """
+ self._ccs.append(email.get())
+
+ @property
+ def bccs(self):
+ """A list of recipients who will receive blind carbon copies of this email.
+
+ :rtype: list(dict)
+ """
+ return self._get_unique_recipients(self._bccs)
+
+ @bccs.setter
+ def bccs(self, value):
+ self._bccs = value
+
+ def add_bcc(self, email):
+ """Add a single recipient to receive a blind carbon copy of this email.
+
+ :param email: new recipient to be BCCed
+ :type email: Email
+ """
+ self._bccs.append(email.get())
+
+ @property
+ def subject(self):
+ """The subject of your email (within this Personalization).
+
+ Char length requirements, according to the RFC:
+ https://stackoverflow.com/a/1592310
+
+ :rtype: string
+ """
+ return self._subject
+
+ @subject.setter
+ def subject(self, value):
+ self._subject = value
+
+ @property
+ def headers(self):
+ """The headers for emails in this Personalization.
+
+ :rtype: list(dict)
+ """
+ return self._headers
+
+ @headers.setter
+ def headers(self, value):
+ self._headers = value
+
+ def add_header(self, header):
+ """Add a single Header to this Personalization.
+
+ :type header: Header
+ """
+ self._headers.append(header.get())
+
+ @property
+ def substitutions(self):
+ """Substitutions to be applied within this Personalization.
+
+ :rtype: list(dict)
+ """
+ return self._substitutions
+
+ @substitutions.setter
+ def substitutions(self, value):
+ self._substitutions = value
+
+ def add_substitution(self, substitution):
+ """Add a new Substitution to this Personalization.
+
+ :type substitution: Substitution
+ """
+ if not isinstance(substitution, dict):
+ substitution = substitution.get()
+
+ self._substitutions.append(substitution)
+
+ @property
+ def custom_args(self):
+ """The CustomArgs that will be carried along with this Personalization.
+
+ :rtype: list(dict)
+ """
+ return self._custom_args
+
+ @custom_args.setter
+ def custom_args(self, value):
+ self._custom_args = value
+
+ def add_custom_arg(self, custom_arg):
+ """Add a CustomArg to this Personalization.
+
+ :type custom_arg: CustomArg
+ """
+ self._custom_args.append(custom_arg.get())
+
+ @property
+ def send_at(self):
+ """A unix timestamp allowing you to specify when you want emails from
+ this Personalization to be delivered. Scheduling more than 72 hours in
+ advance is forbidden.
+
+ :rtype: int
+ """
+ return self._send_at
+
+ @send_at.setter
+ def send_at(self, value):
+ self._send_at = value
+
+ @property
+ def dynamic_template_data(self):
+ """Data for dynamic transactional template.
+ Should be JSON-serializable structure.
+
+ :rtype: JSON-serializable structure
+ """
+ return self._dynamic_template_data
+
+ @dynamic_template_data.setter
+ def dynamic_template_data(self, value):
+ if not isinstance(value, dict):
+ value = value.get()
+
+ self._dynamic_template_data = value
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this Personalization.
+
+ :returns: This Personalization, ready for use in a request body.
+ :rtype: dict
+ """
+ personalization = {}
+
+ for key in ['tos', 'ccs', 'bccs']:
+ value = getattr(self, key)
+ if value:
+ personalization[key[:-1]] = value
+
+ from_value = getattr(self, 'from_email')
+ if from_value:
+ personalization['from'] = from_value
+
+ for key in ['subject', 'send_at', 'dynamic_template_data']:
+ value = getattr(self, key)
+ if value:
+ personalization[key] = value
+
+ for prop_name in ['headers', 'substitutions', 'custom_args']:
+ prop = getattr(self, prop_name)
+ if prop:
+ obj = {}
+ for key in prop:
+ obj.update(key)
+ personalization[prop_name] = obj
+
+ return personalization
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/plain_text_content.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/plain_text_content.py
new file mode 100644
index 00000000..78bce1a8
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/plain_text_content.py
@@ -0,0 +1,60 @@
+from .content import Content
+from .validators import ValidateApiKey
+
+
+class PlainTextContent(Content):
+ """Plain text content to be included in your email.
+ """
+
+ def __init__(self, content):
+ """Create a PlainTextContent with the specified MIME type and content.
+
+ :param content: The actual text content.
+ :type content: string
+ """
+ self._content = None
+ self._validator = ValidateApiKey()
+
+ if content is not None:
+ self.content = content
+
+ @property
+ def mime_type(self):
+ """The MIME type.
+
+ :rtype: string
+ """
+ return "text/plain"
+
+ @property
+ def content(self):
+ """The actual text content.
+
+ :rtype: string
+ """
+ return self._content
+
+ @content.setter
+ def content(self, value):
+ """The actual text content.
+
+ :param value: The actual text content.
+ :type value: string
+ """
+ self._validator.validate_message_dict(value)
+ self._content = value
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this PlainTextContent.
+
+ :returns: This PlainTextContent, ready for use in a request body.
+ :rtype: dict
+ """
+ content = {}
+ if self.mime_type is not None:
+ content["type"] = self.mime_type
+
+ if self.content is not None:
+ content["value"] = self.content
+ return content
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/reply_to.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/reply_to.py
new file mode 100644
index 00000000..731e2ad8
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/reply_to.py
@@ -0,0 +1,5 @@
+from .email import Email
+
+
+class ReplyTo(Email):
+ """A reply to email address with an optional name."""
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/sandbox_mode.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/sandbox_mode.py
new file mode 100644
index 00000000..e8990ee9
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/sandbox_mode.py
@@ -0,0 +1,44 @@
+class SandBoxMode(object):
+ """Setting for sandbox mode.
+ This allows you to send a test email to ensure that your request body is
+ valid and formatted correctly.
+ """
+ def __init__(self, enable=None):
+ """Create an enabled or disabled SandBoxMode.
+
+ :param enable: Whether this is a test request.
+ :type enable: boolean, optional
+ """
+ self._enable = None
+
+ if enable is not None:
+ self.enable = enable
+
+ @property
+ def enable(self):
+ """Indicates if this setting is enabled.
+
+ :rtype: boolean
+ """
+ return self._enable
+
+ @enable.setter
+ def enable(self, value):
+ """Indicates if this setting is enabled.
+
+ :param value: Indicates if this setting is enabled.
+ :type value: boolean
+ """
+ self._enable = value
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this SandBoxMode.
+
+ :returns: This SandBoxMode, ready for use in a request body.
+ :rtype: dict
+ """
+ sandbox_mode = {}
+ if self.enable is not None:
+ sandbox_mode["enable"] = self.enable
+ return sandbox_mode
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/section.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/section.py
new file mode 100644
index 00000000..cea949b1
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/section.py
@@ -0,0 +1,64 @@
+class Section(object):
+ """A block section of code to be used as a substitution."""
+
+ def __init__(self, key=None, value=None):
+ """Create a section with the given key and value.
+
+ :param key: section of code key
+ :type key: string
+ :param value: section of code value
+ :type value: string
+ """
+ self._key = None
+ self._value = None
+
+ if key is not None:
+ self.key = key
+ if value is not None:
+ self.value = value
+
+ @property
+ def key(self):
+ """A section of code's key.
+
+ :rtype key: string
+ """
+ return self._key
+
+ @key.setter
+ def key(self, value):
+ """A section of code's key.
+
+ :param key: section of code key
+ :type key: string
+ """
+ self._key = value
+
+ @property
+ def value(self):
+ """A section of code's value.
+
+ :rtype: string
+ """
+ return self._value
+
+ @value.setter
+ def value(self, value):
+ """A section of code's value.
+
+ :param value: A section of code's value.
+ :type value: string
+ """
+ self._value = value
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this Section.
+
+ :returns: This Section, ready for use in a request body.
+ :rtype: dict
+ """
+ section = {}
+ if self.key is not None and self.value is not None:
+ section[self.key] = self.value
+ return section
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/send_at.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/send_at.py
new file mode 100644
index 00000000..6e3a1541
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/send_at.py
@@ -0,0 +1,79 @@
+class SendAt(object):
+ """A unix timestamp allowing you to specify when you want your
+ email to be delivered. This may be overridden by the
+ personalizations[x].send_at parameter. You can't schedule more
+ than 72 hours in advance. If you have the flexibility, it's
+ better to schedule mail for off-peak times. Most emails are
+ scheduled and sent at the top of the hour or half hour.
+ Scheduling email to avoid those times (for example, scheduling
+ at 10:53) can result in lower deferral rates because it won't
+ be going through our servers at the same times as everyone else's
+ mail."""
+ def __init__(self, send_at=None, p=None):
+ """Create a unix timestamp specifying when your email should
+ be delivered.
+
+ :param send_at: Unix timestamp
+ :type send_at: integer
+ :param name: p is the Personalization object or Personalization object
+ index
+ :type name: Personalization, integer, optional
+ """
+ self._send_at = None
+ self._personalization = None
+
+ if send_at is not None:
+ self.send_at = send_at
+ if p is not None:
+ self.personalization = p
+
+ @property
+ def send_at(self):
+ """A unix timestamp.
+
+ :rtype: integer
+ """
+ return self._send_at
+
+ @send_at.setter
+ def send_at(self, value):
+ """A unix timestamp.
+
+ :param value: A unix timestamp.
+ :type value: integer
+ """
+ self._send_at = value
+
+ @property
+ def personalization(self):
+ """The Personalization object or Personalization object index
+
+ :rtype: Personalization, integer
+ """
+ return self._personalization
+
+ @personalization.setter
+ def personalization(self, value):
+ """The Personalization object or Personalization object index
+
+ :param value: The Personalization object or Personalization object
+ index
+ :type value: Personalization, integer
+ """
+ self._personalization = value
+
+ def __str__(self):
+ """Get a JSON representation of this object.
+
+ :rtype: integer
+ """
+ return str(self.get())
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this SendAt object.
+
+ :returns: The unix timestamp, ready for use in a request body.
+ :rtype: integer
+ """
+ return self.send_at
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/spam_check.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/spam_check.py
new file mode 100644
index 00000000..c584f8cf
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/spam_check.py
@@ -0,0 +1,112 @@
+from .spam_threshold import SpamThreshold
+from .spam_url import SpamUrl
+
+
+class SpamCheck(object):
+ """This allows you to test the content of your email for spam."""
+
+ def __init__(self, enable=None, threshold=None, post_to_url=None):
+ """Create a SpamCheck to test the content of your email for spam.
+
+ :param enable: If this setting is applied.
+ :type enable: boolean, optional
+ :param threshold: Spam qualification threshold, from 1 to 10 (strict).
+ :type threshold: int, optional
+ :param post_to_url: Inbound Parse URL to send a copy of your email.
+ :type post_to_url: string, optional
+ """
+ self._enable = None
+ self._threshold = None
+ self._post_to_url = None
+
+ if enable is not None:
+ self.enable = enable
+ if threshold is not None:
+ self.threshold = threshold
+ if post_to_url is not None:
+ self.post_to_url = post_to_url
+
+ @property
+ def enable(self):
+ """Indicates if this setting is enabled.
+
+ :rtype: boolean
+ """
+ return self._enable
+
+ @enable.setter
+ def enable(self, value):
+ """Indicates if this setting is enabled.
+
+ :param value: Indicates if this setting is enabled.
+ :type value: boolean
+ """
+ self._enable = value
+
+ @property
+ def threshold(self):
+ """Threshold used to determine if your content qualifies as spam.
+ On a scale from 1 to 10, with 10 being most strict, or most likely to
+ be considered as spam.
+
+ :rtype: int
+ """
+ return self._threshold
+
+ @threshold.setter
+ def threshold(self, value):
+ """Threshold used to determine if your content qualifies as spam.
+ On a scale from 1 to 10, with 10 being most strict, or most likely to
+ be considered as spam.
+
+ :param value: Threshold used to determine if your content qualifies as
+ spam.
+ On a scale from 1 to 10, with 10 being most strict, or
+ most likely to be considered as spam.
+ :type value: int
+ """
+ if isinstance(value, SpamThreshold):
+ self._threshold = value
+ else:
+ self._threshold = SpamThreshold(value)
+
+ @property
+ def post_to_url(self):
+ """An Inbound Parse URL to send a copy of your email.
+ If defined, a copy of your email and its spam report will be sent here.
+
+ :rtype: string
+ """
+ return self._post_to_url
+
+ @post_to_url.setter
+ def post_to_url(self, value):
+ """An Inbound Parse URL to send a copy of your email.
+ If defined, a copy of your email and its spam report will be sent here.
+
+ :param value: An Inbound Parse URL to send a copy of your email.
+ If defined, a copy of your email and its spam report will be sent here.
+ :type value: string
+ """
+ if isinstance(value, SpamUrl):
+ self._post_to_url = value
+ else:
+ self._post_to_url = SpamUrl(value)
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this SpamCheck.
+
+ :returns: This SpamCheck, ready for use in a request body.
+ :rtype: dict
+ """
+ spam_check = {}
+ if self.enable is not None:
+ spam_check["enable"] = self.enable
+
+ if self.threshold is not None:
+ spam_check["threshold"] = self.threshold.get()
+
+ if self.post_to_url is not None:
+ spam_check["post_to_url"] = self.post_to_url.get()
+ return spam_check
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/spam_threshold.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/spam_threshold.py
new file mode 100644
index 00000000..45053dbd
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/spam_threshold.py
@@ -0,0 +1,53 @@
+class SpamThreshold(object):
+ """The threshold used to determine if your content qualifies as spam
+ on a scale from 1 to 10, with 10 being most strict, or most likely
+ to be considered as spam."""
+
+ def __init__(self, spam_threshold=None):
+ """Create a SpamThreshold object
+
+ :param spam_threshold: The threshold used to determine if your content
+ qualifies as spam on a scale from 1 to 10, with
+ 10 being most strict, or most likely to be
+ considered as spam.
+ :type spam_threshold: integer, optional
+ """
+ self._spam_threshold = None
+
+ if spam_threshold is not None:
+ self.spam_threshold = spam_threshold
+
+ @property
+ def spam_threshold(self):
+ """The threshold used to determine if your content
+ qualifies as spam on a scale from 1 to 10, with
+ 10 being most strict, or most likely to be
+ considered as spam.
+
+ :rtype: integer
+ """
+ return self._spam_threshold
+
+ @spam_threshold.setter
+ def spam_threshold(self, value):
+ """The threshold used to determine if your content
+ qualifies as spam on a scale from 1 to 10, with
+ 10 being most strict, or most likely to be
+ considered as spam.
+
+ :param value: The threshold used to determine if your content
+ qualifies as spam on a scale from 1 to 10, with
+ 10 being most strict, or most likely to be
+ considered as spam.
+ :type value: integer
+ """
+ self._spam_threshold = value
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this SpamThreshold.
+
+ :returns: This SpamThreshold, ready for use in a request body.
+ :rtype: integer
+ """
+ return self.spam_threshold
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/spam_url.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/spam_url.py
new file mode 100644
index 00000000..529438ce
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/spam_url.py
@@ -0,0 +1,44 @@
+class SpamUrl(object):
+ """An Inbound Parse URL that you would like a copy of your email
+ along with the spam report to be sent to."""
+
+ def __init__(self, spam_url=None):
+ """Create a SpamUrl object
+
+ :param spam_url: An Inbound Parse URL that you would like a copy of
+ your email along with the spam report to be sent to.
+ :type spam_url: string, optional
+ """
+ self._spam_url = None
+
+ if spam_url is not None:
+ self.spam_url = spam_url
+
+ @property
+ def spam_url(self):
+ """An Inbound Parse URL that you would like a copy of your email
+ along with the spam report to be sent to.
+
+ :rtype: string
+ """
+ return self._spam_url
+
+ @spam_url.setter
+ def spam_url(self, value):
+ """An Inbound Parse URL that you would like a copy of your email
+ along with the spam report to be sent to.
+
+ :param value: An Inbound Parse URL that you would like a copy of your
+ email along with the spam report to be sent to.
+ :type value: string
+ """
+ self._spam_url = value
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this SpamUrl.
+
+ :returns: This SpamUrl, ready for use in a request body.
+ :rtype: string
+ """
+ return self.spam_url
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/subject.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/subject.py
new file mode 100644
index 00000000..1637f400
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/subject.py
@@ -0,0 +1,69 @@
+class Subject(object):
+ """A subject for an email message."""
+
+ def __init__(self, subject, p=None):
+ """Create a Subject.
+
+ :param subject: The subject for an email
+ :type subject: string
+ :param name: p is the Personalization object or Personalization object
+ index
+ :type name: Personalization, integer, optional
+ """
+ self._subject = None
+ self._personalization = None
+
+ self.subject = subject
+ if p is not None:
+ self.personalization = p
+
+ @property
+ def subject(self):
+ """The subject of an email.
+
+ :rtype: string
+ """
+ return self._subject
+
+ @subject.setter
+ def subject(self, value):
+ """The subject of an email.
+
+ :param value: The subject of an email.
+ :type value: string
+ """
+ self._subject = value
+
+ @property
+ def personalization(self):
+ """The Personalization object or Personalization object index
+
+ :rtype: Personalization, integer
+ """
+ return self._personalization
+
+ @personalization.setter
+ def personalization(self, value):
+ """The Personalization object or Personalization object index
+
+ :param value: The Personalization object or Personalization object
+ index
+ :type value: Personalization, integer
+ """
+ self._personalization = value
+
+ def __str__(self):
+ """Get a JSON representation of this Mail request.
+
+ :rtype: string
+ """
+ return str(self.get())
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this Subject.
+
+ :returns: This Subject, ready for use in a request body.
+ :rtype: string
+ """
+ return self.subject
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/subscription_html.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/subscription_html.py
new file mode 100644
index 00000000..bfe8629f
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/subscription_html.py
@@ -0,0 +1,45 @@
+class SubscriptionHtml(object):
+ """The HTML of an SubscriptionTracking."""
+
+ def __init__(self, subscription_html=None):
+ """Create a SubscriptionHtml object
+
+ :param subscription_html: Html to be appended to the email, with the
+ subscription tracking link. You may control
+ where the link is by using the tag <% %>
+ :type subscription_html: string, optional
+ """
+ self._subscription_html = None
+
+ if subscription_html is not None:
+ self.subscription_html = subscription_html
+
+ @property
+ def subscription_html(self):
+ """Html to be appended to the email, with the subscription tracking link.
+ You may control where the link is by using the tag <% %>
+
+ :rtype: string
+ """
+ return self._subscription_html
+
+ @subscription_html.setter
+ def subscription_html(self, value):
+ """Html to be appended to the email, with the subscription tracking link.
+ You may control where the link is by using the tag <% %>
+
+ :param value: Html to be appended to the email, with the subscription
+ tracking link. You may control where the link is by using
+ the tag <% %>
+ :type value: string
+ """
+ self._subscription_html = value
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this SubscriptionHtml.
+
+ :returns: This SubscriptionHtml, ready for use in a request body.
+ :rtype: string
+ """
+ return self.subscription_html
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/subscription_substitution_tag.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/subscription_substitution_tag.py
new file mode 100644
index 00000000..9a7d6a95
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/subscription_substitution_tag.py
@@ -0,0 +1,58 @@
+class SubscriptionSubstitutionTag(object):
+ """The subscription substitution tag of an SubscriptionTracking."""
+
+ def __init__(self, subscription_substitution_tag=None):
+ """Create a SubscriptionSubstitutionTag object
+
+ :param subscription_substitution_tag: A tag that will be replaced with
+ the unsubscribe URL. for example:
+ [unsubscribe_url]. If this
+ parameter is used, it will
+ override both the text and html
+ parameters. The URL of the link
+ will be placed at the
+ substitution tag's location,
+ with no additional formatting.
+ :type subscription_substitution_tag: string, optional
+ """
+ self._subscription_substitution_tag = None
+
+ if subscription_substitution_tag is not None:
+ self.subscription_substitution_tag = subscription_substitution_tag
+
+ @property
+ def subscription_substitution_tag(self):
+ """A tag that will be replaced with the unsubscribe URL. for example:
+ [unsubscribe_url]. If this parameter is used, it will override both
+ the text and html parameters. The URL of the link will be placed at
+ the substitution tag's location, with no additional formatting.
+
+ :rtype: string
+ """
+ return self._subscription_substitution_tag
+
+ @subscription_substitution_tag.setter
+ def subscription_substitution_tag(self, value):
+ """A tag that will be replaced with the unsubscribe URL. for example:
+ [unsubscribe_url]. If this parameter is used, it will override both
+ the text and html parameters. The URL of the link will be placed at
+ the substitution tag's location, with no additional formatting.
+
+ :param value: A tag that will be replaced with the unsubscribe URL.
+ for example: [unsubscribe_url]. If this parameter is
+ used, it will override both the text and html parameters.
+ The URL of the link will be placed at the substitution
+ tag's location, with no additional formatting.
+ :type value: string
+ """
+ self._subscription_substitution_tag = value
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this SubscriptionSubstitutionTag.
+
+ :returns: This SubscriptionSubstitutionTag, ready for use in a request
+ body.
+ :rtype: string
+ """
+ return self.subscription_substitution_tag
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/subscription_text.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/subscription_text.py
new file mode 100644
index 00000000..ca20894a
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/subscription_text.py
@@ -0,0 +1,45 @@
+class SubscriptionText(object):
+ """The text of an SubscriptionTracking."""
+
+ def __init__(self, subscription_text=None):
+ """Create a SubscriptionText object
+
+ :param subscription_text: Text to be appended to the email, with the
+ subscription tracking link. You may control
+ where the link is by using the tag <% %>
+ :type subscription_text: string, optional
+ """
+ self._subscription_text = None
+
+ if subscription_text is not None:
+ self.subscription_text = subscription_text
+
+ @property
+ def subscription_text(self):
+ """Text to be appended to the email, with the subscription tracking link.
+ You may control where the link is by using the tag <% %>
+
+ :rtype: string
+ """
+ return self._subscription_text
+
+ @subscription_text.setter
+ def subscription_text(self, value):
+ """Text to be appended to the email, with the subscription tracking link.
+ You may control where the link is by using the tag <% %>
+
+ :param value: Text to be appended to the email, with the subscription
+ tracking link. You may control where the link is by using
+ the tag <% %>
+ :type value: string
+ """
+ self._subscription_text = value
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this SubscriptionText.
+
+ :returns: This SubscriptionText, ready for use in a request body.
+ :rtype: string
+ """
+ return self.subscription_text
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/subscription_tracking.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/subscription_tracking.py
new file mode 100644
index 00000000..8db65372
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/subscription_tracking.py
@@ -0,0 +1,142 @@
+class SubscriptionTracking(object):
+ """Allows you to insert a subscription management link at the bottom of the
+ text and html bodies of your email. If you would like to specify the
+ location of the link within your email, you may use the substitution_tag.
+ """
+
+ def __init__(
+ self, enable=None, text=None, html=None, substitution_tag=None):
+ """Create a SubscriptionTracking to customize subscription management.
+
+ :param enable: Whether this setting is enabled.
+ :type enable: boolean, optional
+ :param text: Text to be appended to the email with the link as "<% %>".
+ :type text: SubscriptionText, optional
+ :param html: HTML to be appended to the email with the link as "<% %>".
+ :type html: SubscriptionHtml, optional
+ :param substitution_tag: Tag replaced with URL. Overrides text, html
+ params.
+ :type substitution_tag: SubscriptionSubstitutionTag, optional
+ """
+ self._enable = None
+ self._text = None
+ self._html = None
+ self._substitution_tag = None
+
+ if enable is not None:
+ self.enable = enable
+ if text is not None:
+ self.text = text
+ if html is not None:
+ self.html = html
+ if substitution_tag is not None:
+ self.substitution_tag = substitution_tag
+
+ @property
+ def enable(self):
+ """Indicates if this setting is enabled.
+
+ :rtype: boolean
+ """
+ return self._enable
+
+ @enable.setter
+ def enable(self, value):
+ """Indicates if this setting is enabled.
+
+ :param value: Indicates if this setting is enabled.
+ :type value: boolean
+ """
+ self._enable = value
+
+ @property
+ def text(self):
+ """Text to be appended to the email, with the subscription tracking
+ link. You may control where the link is by using the tag <% %>
+
+ :rtype: string
+ """
+ return self._text
+
+ @text.setter
+ def text(self, value):
+ """Text to be appended to the email, with the subscription tracking
+ link. You may control where the link is by using the tag <% %>
+
+ :param value: Text to be appended to the email, with the subscription
+ tracking link. You may control where the link is by
+ using the tag <% %>
+ :type value: string
+ """
+ self._text = value
+
+ @property
+ def html(self):
+ """HTML to be appended to the email, with the subscription tracking
+ link. You may control where the link is by using the tag <% %>
+
+ :rtype: string
+ """
+ return self._html
+
+ @html.setter
+ def html(self, value):
+ """HTML to be appended to the email, with the subscription tracking
+ link. You may control where the link is by using the tag <% %>
+
+ :param value: HTML to be appended to the email, with the subscription
+ tracking link. You may control where the link is by
+ using the tag <% %>
+ :type value: string
+ """
+ self._html = value
+
+ @property
+ def substitution_tag(self):
+ """"A tag that will be replaced with the unsubscribe URL. for example:
+ [unsubscribe_url]. If this parameter is used, it will override both the
+ `text` and `html` parameters. The URL of the link will be placed at the
+ substitution tag's location, with no additional formatting.
+
+ :rtype: string
+ """
+ return self._substitution_tag
+
+ @substitution_tag.setter
+ def substitution_tag(self, value):
+ """"A tag that will be replaced with the unsubscribe URL. for example:
+ [unsubscribe_url]. If this parameter is used, it will override both the
+ `text` and `html` parameters. The URL of the link will be placed at the
+ substitution tag's location, with no additional formatting.
+
+ :param value: A tag that will be replaced with the unsubscribe URL.
+ For example: [unsubscribe_url]. If this parameter is
+ used, it will override both the `text` and `html`
+ parameters. The URL of the link will be placed at the
+ substitution tag's location, with no additional
+ formatting.
+ :type value: string
+ """
+ self._substitution_tag = value
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this SubscriptionTracking.
+
+ :returns: This SubscriptionTracking, ready for use in a request body.
+ :rtype: dict
+ """
+ subscription_tracking = {}
+ if self.enable is not None:
+ subscription_tracking["enable"] = self.enable
+
+ if self.text is not None:
+ subscription_tracking["text"] = self.text.get()
+
+ if self.html is not None:
+ subscription_tracking["html"] = self.html.get()
+
+ if self.substitution_tag is not None:
+ subscription_tracking["substitution_tag"] = \
+ self.substitution_tag.get()
+ return subscription_tracking
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/substitution.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/substitution.py
new file mode 100644
index 00000000..d515e885
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/substitution.py
@@ -0,0 +1,90 @@
+class Substitution(object):
+ """A string substitution to be applied to the text and HTML contents of
+ the body of your email, as well as in the Subject and Reply-To parameters.
+ """
+
+ def __init__(self, key=None, value=None, p=None):
+ """Create a Substitution with the given key and value.
+
+ :param key: Text to be replaced with "value" param
+ :type key: string, optional
+ :param value: Value to substitute into email
+ :type value: string, optional
+ :param name: p is the Personalization object or Personalization object
+ index
+ :type name: Personalization, integer, optional
+ """
+ self._key = None
+ self._value = None
+ self._personalization = None
+
+ if key is not None:
+ self.key = key
+ if value is not None:
+ self.value = value
+ if p is not None:
+ self.personalization = p
+
+ @property
+ def key(self):
+ """The substitution key.
+
+ :rtype key: string
+ """
+ return self._key
+
+ @key.setter
+ def key(self, value):
+ """The substitution key.
+
+ :param key: The substitution key.
+ :type key: string
+ """
+ self._key = value
+
+ @property
+ def value(self):
+ """The substitution value.
+
+ :rtype value: string
+ """
+ return str(self._value) if isinstance(self._value, int) else self._value
+
+ @value.setter
+ def value(self, value):
+ """The substitution value.
+
+ :param value: The substitution value.
+ :type value: string
+ """
+ self._value = value
+
+ @property
+ def personalization(self):
+ """The Personalization object or Personalization object index
+
+ :rtype: Personalization, integer
+ """
+ return self._personalization
+
+ @personalization.setter
+ def personalization(self, value):
+ """The Personalization object or Personalization object index
+
+ :param value: The Personalization object or Personalization object
+ index
+ :type value: Personalization, integer
+ """
+ self._personalization = value
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this Substitution.
+
+ :returns: This Substitution, ready for use in a request body.
+ :rtype: dict
+ """
+ substitution = {}
+ if self.key is not None and self.value is not None:
+ substitution[self.key] = self.value
+ return substitution
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/template_id.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/template_id.py
new file mode 100644
index 00000000..f18c5f58
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/template_id.py
@@ -0,0 +1,39 @@
+class TemplateId(object):
+ """The template ID of an Attachment object."""
+
+ def __init__(self, template_id=None):
+ """Create a TemplateId object
+
+ :param template_id: The template id for the message
+ :type template_id: string, optional
+ """
+ self._template_id = None
+
+ if template_id is not None:
+ self.template_id = template_id
+
+ @property
+ def template_id(self):
+ """The template id for the message
+
+ :rtype: string
+ """
+ return self._template_id
+
+ @template_id.setter
+ def template_id(self, value):
+ """The template id for the message
+
+ :param value: The template id for the message
+ :type value: string
+ """
+ self._template_id = value
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this TemplateId.
+
+ :returns: This TemplateId, ready for use in a request body.
+ :rtype: string
+ """
+ return self.template_id
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/to_email.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/to_email.py
new file mode 100644
index 00000000..e4f294f0
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/to_email.py
@@ -0,0 +1,5 @@
+from .email import Email
+
+
+class To(Email):
+ """A to email address with an optional name."""
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/tracking_settings.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/tracking_settings.py
new file mode 100644
index 00000000..d5f2e4fd
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/tracking_settings.py
@@ -0,0 +1,134 @@
+class TrackingSettings(object):
+ """Settings to track how recipients interact with your email."""
+
+ def __init__(self,
+ click_tracking=None,
+ open_tracking=None,
+ subscription_tracking=None,
+ ganalytics=None):
+ """Create a TrackingSettings object
+
+ :param click_tracking: Allows you to track whether a recipient clicked
+ a link in your email.
+ :type click_tracking: ClickTracking, optional
+ :param open_tracking: Allows you to track whether the email was opened
+ or not, but including a single pixel image in
+ the body of the content. When the pixel is
+ loaded, we can log that the email was opened.
+ :type open_tracking: OpenTracking, optional
+ :param subscription_tracking: Allows you to insert a subscription
+ management link at the bottom of the
+ text and html bodies of your email. If
+ you would like to specify the location
+ of the link within your email, you may
+ use the substitution_tag.
+ :type subscription_tracking: SubscriptionTracking, optional
+ :param ganalytics: Allows you to enable tracking provided by Google
+ Analytics.
+ :type ganalytics: Ganalytics, optional
+ """
+ self._click_tracking = None
+ self._open_tracking = None
+ self._subscription_tracking = None
+ self._ganalytics = None
+
+ if click_tracking is not None:
+ self._click_tracking = click_tracking
+
+ if open_tracking is not None:
+ self._open_tracking = open_tracking
+
+ if subscription_tracking is not None:
+ self._subscription_tracking = subscription_tracking
+
+ if ganalytics is not None:
+ self._ganalytics = ganalytics
+
+ @property
+ def click_tracking(self):
+ """Allows you to track whether a recipient clicked a link in your email.
+
+ :rtype: ClickTracking
+ """
+ return self._click_tracking
+
+ @click_tracking.setter
+ def click_tracking(self, value):
+ """Allows you to track whether a recipient clicked a link in your email.
+
+ :param value: Allows you to track whether a recipient clicked a link
+ in your email.
+ :type value: ClickTracking
+ """
+ self._click_tracking = value
+
+ @property
+ def open_tracking(self):
+ """Allows you to track whether a recipient opened your email.
+
+ :rtype: OpenTracking
+ """
+ return self._open_tracking
+
+ @open_tracking.setter
+ def open_tracking(self, value):
+ """Allows you to track whether a recipient opened your email.
+
+ :param value: Allows you to track whether a recipient opened your
+ email.
+ :type value: OpenTracking
+ """
+ self._open_tracking = value
+
+ @property
+ def subscription_tracking(self):
+ """Settings for the subscription management link.
+
+ :rtype: SubscriptionTracking
+ """
+ return self._subscription_tracking
+
+ @subscription_tracking.setter
+ def subscription_tracking(self, value):
+ """Settings for the subscription management link.
+
+ :param value: Settings for the subscription management link.
+ :type value: SubscriptionTracking
+ """
+ self._subscription_tracking = value
+
+ @property
+ def ganalytics(self):
+ """Settings for Google Analytics.
+
+ :rtype: Ganalytics
+ """
+ return self._ganalytics
+
+ @ganalytics.setter
+ def ganalytics(self, value):
+ """Settings for Google Analytics.
+
+ :param value: Settings for Google Analytics.
+ :type value: Ganalytics
+ """
+ self._ganalytics = value
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this TrackingSettings.
+
+ :returns: This TrackingSettings, ready for use in a request body.
+ :rtype: dict
+ """
+ tracking_settings = {}
+ if self.click_tracking is not None:
+ tracking_settings["click_tracking"] = self.click_tracking.get()
+ if self.open_tracking is not None:
+ tracking_settings["open_tracking"] = self.open_tracking.get()
+ if self.subscription_tracking is not None:
+ tracking_settings[
+ "subscription_tracking"] = self.subscription_tracking.get()
+ if self.ganalytics is not None:
+ tracking_settings["ganalytics"] = self.ganalytics.get()
+ return tracking_settings
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/utm_campaign.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/utm_campaign.py
new file mode 100644
index 00000000..5b200682
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/utm_campaign.py
@@ -0,0 +1,40 @@
+class UtmCampaign(object):
+ """The utm campaign of an Ganalytics object."""
+
+ def __init__(self, utm_campaign=None):
+ """Create a UtmCampaign object
+
+ :param utm_campaign: The name of the campaign
+
+ :type utm_campaign: string, optional
+ """
+ self._utm_campaign = None
+
+ if utm_campaign is not None:
+ self.utm_campaign = utm_campaign
+
+ @property
+ def utm_campaign(self):
+ """The name of the campaign
+
+ :rtype: string
+ """
+ return self._utm_campaign
+
+ @utm_campaign.setter
+ def utm_campaign(self, value):
+ """The name of the campaign
+
+ :param value: The name of the campaign
+ :type value: string
+ """
+ self._utm_campaign = value
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this UtmCampaign.
+
+ :returns: This UtmCampaign, ready for use in a request body.
+ :rtype: string
+ """
+ return self.utm_campaign
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/utm_content.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/utm_content.py
new file mode 100644
index 00000000..e2a8ccff
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/utm_content.py
@@ -0,0 +1,40 @@
+class UtmContent(object):
+ """The utm content of an Ganalytics object."""
+
+ def __init__(self, utm_content=None):
+ """Create a UtmContent object
+
+ :param utm_content: Used to differentiate your campaign from advertisements.
+
+ :type utm_content: string, optional
+ """
+ self._utm_content = None
+
+ if utm_content is not None:
+ self.utm_content = utm_content
+
+ @property
+ def utm_content(self):
+ """Used to differentiate your campaign from advertisements.
+
+ :rtype: string
+ """
+ return self._utm_content
+
+ @utm_content.setter
+ def utm_content(self, value):
+ """Used to differentiate your campaign from advertisements.
+
+ :param value: Used to differentiate your campaign from advertisements.
+ :type value: string
+ """
+ self._utm_content = value
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this UtmContent.
+
+ :returns: This UtmContent, ready for use in a request body.
+ :rtype: string
+ """
+ return self.utm_content
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/utm_medium.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/utm_medium.py
new file mode 100644
index 00000000..3687a0b2
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/utm_medium.py
@@ -0,0 +1,40 @@
+class UtmMedium(object):
+ """The utm medium of an Ganalytics object."""
+
+ def __init__(self, utm_medium=None):
+ """Create a UtmMedium object
+
+ :param utm_medium: Name of the marketing medium. (e.g. Email)
+
+ :type utm_medium: string, optional
+ """
+ self._utm_medium = None
+
+ if utm_medium is not None:
+ self.utm_medium = utm_medium
+
+ @property
+ def utm_medium(self):
+ """Name of the marketing medium. (e.g. Email)
+
+ :rtype: string
+ """
+ return self._utm_medium
+
+ @utm_medium.setter
+ def utm_medium(self, value):
+ """Name of the marketing medium. (e.g. Email)
+
+ :param value: Name of the marketing medium. (e.g. Email)
+ :type value: string
+ """
+ self._utm_medium = value
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this UtmMedium.
+
+ :returns: This UtmMedium, ready for use in a request body.
+ :rtype: string
+ """
+ return self.utm_medium
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/utm_source.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/utm_source.py
new file mode 100644
index 00000000..841ba0a8
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/utm_source.py
@@ -0,0 +1,43 @@
+class UtmSource(object):
+ """The utm source of an Ganalytics object."""
+
+ def __init__(self, utm_source=None):
+ """Create a UtmSource object
+
+ :param utm_source: Name of the referrer source.
+ (e.g. Google, SomeDomain.com, or Marketing Email)
+ :type utm_source: string, optional
+ """
+ self._utm_source = None
+
+ if utm_source is not None:
+ self.utm_source = utm_source
+
+ @property
+ def utm_source(self):
+ """Name of the referrer source. (e.g. Google, SomeDomain.com, or
+ Marketing Email)
+
+ :rtype: string
+ """
+ return self._utm_source
+
+ @utm_source.setter
+ def utm_source(self, value):
+ """Name of the referrer source. (e.g. Google, SomeDomain.com, or
+ Marketing Email)
+
+ :param value: Name of the referrer source.
+ (e.g. Google, SomeDomain.com, or Marketing Email)
+ :type value: string
+ """
+ self._utm_source = value
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this UtmSource.
+
+ :returns: This UtmSource, ready for use in a request body.
+ :rtype: string
+ """
+ return self.utm_source
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/utm_term.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/utm_term.py
new file mode 100644
index 00000000..e8a9518a
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/utm_term.py
@@ -0,0 +1,40 @@
+class UtmTerm(object):
+ """The utm term of an Ganalytics object."""
+
+ def __init__(self, utm_term=None):
+ """Create a UtmTerm object
+
+ :param utm_term: Used to identify any paid keywords.
+
+ :type utm_term: string, optional
+ """
+ self._utm_term = None
+
+ if utm_term is not None:
+ self.utm_term = utm_term
+
+ @property
+ def utm_term(self):
+ """Used to identify any paid keywords.
+
+ :rtype: string
+ """
+ return self._utm_term
+
+ @utm_term.setter
+ def utm_term(self, value):
+ """Used to identify any paid keywords.
+
+ :param value: Used to identify any paid keywords.
+ :type value: string
+ """
+ self._utm_term = value
+
+ def get(self):
+ """
+ Get a JSON-ready representation of this UtmTerm.
+
+ :returns: This UtmTerm, ready for use in a request body.
+ :rtype: string
+ """
+ return self.utm_term
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/validators.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/validators.py
new file mode 100644
index 00000000..00e3276e
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/validators.py
@@ -0,0 +1,69 @@
+from .exceptions import ApiKeyIncludedException
+
+
+class ValidateApiKey(object):
+ """Validates content to ensure SendGrid API key is not present"""
+
+ regexes = None
+
+ def __init__(self, regex_strings=None, use_default=True):
+ """Create an API key validator
+
+ :param regex_strings: list of regex strings
+ :type regex_strings: list(str)
+ :param use_default: Whether or not to include default regex
+ :type use_default: bool
+ """
+
+ import re
+ self.regexes = set()
+
+ # Compile the regex strings into patterns, add them to our set
+ if regex_strings is not None:
+ for regex_string in regex_strings:
+ self.regexes.add(re.compile(regex_string))
+
+ if use_default:
+ default_regex_string = r'SG\.[0-9a-zA-Z]+\.[0-9a-zA-Z]+'
+ self.regexes.add(re.compile(default_regex_string))
+
+ def validate_message_dict(self, request_body):
+ """With the JSON dict that will be sent to SendGrid's API,
+ check the content for SendGrid API keys - throw exception if found.
+
+ :param request_body: The JSON dict that will be sent to SendGrid's
+ API.
+ :type request_body: JSON serializable structure
+ :raise ApiKeyIncludedException: If any content in request_body
+ matches regex
+ """
+
+ # Handle string in edge-case
+ if isinstance(request_body, str):
+ self.validate_message_text(request_body)
+
+ # Default param
+ elif isinstance(request_body, dict):
+
+ contents = request_body.get("content", list())
+
+ for content in contents:
+ if content is not None:
+ if (content.get("type") == "text/html" or
+ isinstance(content.get("value"), str)):
+ message_text = content.get("value", "")
+ self.validate_message_text(message_text)
+
+ def validate_message_text(self, message_string):
+ """With a message string, check to see if it contains a SendGrid API Key
+ If a key is found, throw an exception
+
+ :param message_string: message that will be sent
+ :type message_string: string
+ :raises ApiKeyIncludedException: If message_string matches a regex
+ string
+ """
+ if isinstance(message_string, str):
+ for regex in self.regexes:
+ if regex.match(message_string) is not None:
+ raise ApiKeyIncludedException()