SendGrid

The Canvas SDK SendGrid client provides a simple interface for sending emails, managing webhooks, and querying email logs using the SendGrid API.

Requirements #

  • SendGrid API Key: Create one at https://app.sendgrid.com/settings/api_keys
  • Authenticated Domain: Configure at https://app.sendgrid.com/settings/sender_auth

Imports #

The SendGrid client is included in the Canvas SDK. Import the necessary components:

from canvas_sdk.clients.sendgrid.libraries import EmailClient
from canvas_sdk.clients.sendgrid.constants import RecipientType
from canvas_sdk.clients.sendgrid.structures import (
    Address,
    BodyContent,
    Email,
    Recipient,
    RequestFailed,
    Settings,
)

Initialize the Client #

client = EmailClient(Settings(key="your_sendgrid_api_key"))

Send a Simple Text Email #

from canvas_sdk.clients.sendgrid.libraries import EmailClient
from canvas_sdk.clients.sendgrid.constants import RecipientType
from canvas_sdk.clients.sendgrid.structures import (
    Address, BodyContent, Email, Recipient, RequestFailed, Settings
)

client = EmailClient(Settings(key="your_api_key"))

email = Email(
    sender=Address(email="sender@example.com", name="Sender Name"),
    reply_tos=[Address(email="reply@example.com", name="Reply To")],
    recipients=[
        Recipient(address=Address(email="recipient@example.com", name="Recipient"), type=RecipientType.TO)
    ],
    subject="Hello from Canvas SDK",
    bodies=[BodyContent(type="text/plain", value="This is a test email.")],
    attachments=[],
    send_at=Email.now(),
)

try:
    client.simple_send(email)
    print("Email sent successfully!")
except RequestFailed as e:
    print(f"Failed to send email: {e.message} (HTTP {e.status_code})")

Send an HTML Email with CC #

email = Email(
    sender=Address(email="sender@example.com", name="Sender"),
    reply_tos=[Address(email="reply@example.com", name="Reply To")],
    recipients=[
        Recipient(address=Address(email="to@example.com", name="To"), type=RecipientType.TO),
        Recipient(address=Address(email="cc@example.com", name="CC"), type=RecipientType.CC),
    ],
    subject="HTML Email Example",
    bodies=[
        BodyContent(type="text/plain", value="Plain text fallback"),
        BodyContent(type="text/html", value="<html><body><h1>Hello!</h1><p>This is HTML content.</p></body></html>"),
    ],
    attachments=[],
    send_at=Email.now(),
)

client.simple_send(email)

Send an Email with Attachment #

from canvas_sdk.clients.sendgrid.structures import Attachment

# Create attachment from URL
attachment = Attachment.from_url(
    url="https://example.com/document.pdf",
    headers={},
    filename="document.pdf"
)

email = Email(
    sender=Address(email="sender@example.com", name="Sender"),
    reply_tos=[Address(email="reply@example.com", name="Reply To")],
    recipients=[
        Recipient(address=Address(email="to@example.com", name="To"), type=RecipientType.TO)
    ],
    subject="Email with Attachment",
    bodies=[BodyContent(type="text/plain", value="Please find attached document.")],
    attachments=[attachment],
    send_at=Email.now(),
)

client.simple_send(email)

Send an Email with Inline Image #

# Create inline image attachment
inline_image = Attachment.from_url_inline(
    url="https://example.com/logo.png",
    headers={},
    filename="logo.png",
    content_id="logo123"
)

email = Email(
    sender=Address(email="sender@example.com", name="Sender"),
    reply_tos=[Address(email="reply@example.com", name="Reply To")],
    recipients=[
        Recipient(address=Address(email="to@example.com", name="To"), type=RecipientType.TO)
    ],
    subject="Email with Inline Image",
    bodies=[
        BodyContent(type="text/plain", value="See image in HTML version"),
        BodyContent(type="text/html", value='<html><body><img src="cid:logo123" width="200"/></body></html>'),
    ],
    attachments=[inline_image],
    send_at=Email.now(),
)

client.simple_send(email)

Query Sent Emails #

from datetime import datetime
from canvas_sdk.clients.sendgrid.constants import CriterionOperation
from canvas_sdk.clients.sendgrid.structures import CriterionDatetime, LoggedEmailCriteria

criteria = LoggedEmailCriteria(
    message_id="",
    subject="",
    to_email="recipient@example.com",
    reason="",
    status=[],
    message_created_at=[
        CriterionDatetime(
            date_time=datetime(2024, 1, 1),
            operation=CriterionOperation.GREATER_THAN_OR_EQUAL
        )
    ],
)

for email in client.logged_emails(criteria, up_to=10):
    print(f"Subject: {email.subject}, Status: {email.status.value}")

EmailClient #

The main class for interacting with the SendGrid API.

Constructor #

EmailClient(settings: Settings)
ParameterTypeDescription
settingsSettingsConfiguration object containing the API key

Sending Emails #

simple_send(email: Email) -> bool #

Send an email using a structured Email object. This is the recommended method for most use cases.

Returns: True on success

Raises: RequestFailed on error

prepared_send(data: dict) -> bool #

Send an email using a raw dictionary following SendGrid’s API schema. Use this for advanced cases not covered by simple_send.

Parameters:

Returns: True on success

Raises: RequestFailed on error

Email Logs #

logged_emails(criteria: LoggedEmailCriteria, up_to: int) -> Iterator[SentEmail] #

Query sent emails matching the specified criteria.

Parameters:

  • criteria: Filter criteria for the query
  • up_to: Maximum number of results to return

Returns: Iterator of SentEmail objects

logged_email(message_id: str) -> SentEmailDetail #

Get detailed information about a specific email including its event history.

Parameters:

  • message_id: The SendGrid message ID

Returns: SentEmailDetail object with full event history

Inbound Parse Webhooks #

Configure webhooks to receive incoming emails.

MethodDescription
parser_setting_add(setting: ParseSetting) -> ParseSettingCreate a new inbound parse webhook
parser_setting_delete(hostname: str) -> boolDelete a webhook by hostname
parser_setting_get(hostname: str) -> ParseSettingGet webhook configuration by hostname
parser_setting_list() -> Iterator[ParseSetting]List all inbound parse webhooks

Requires MX record setup pointing to mx.sendgrid.net, for example:

hosttypepriorityTTLvalue
canvasMX101 hrmx.sendgrid.net

Event Webhooks #

Configure webhooks to receive email delivery status notifications.

MethodDescription
event_webhook_add(event: EventWebhook) -> EventWebhookRecordCreate a new event webhook
event_webhook_delete(event_webhook_id: str) -> boolDelete a webhook by ID
event_webhook_get(event_webhook_id: str) -> EventWebhookRecordGet webhook by ID
event_webhook_list() -> Iterator[EventWebhookRecord]List all event webhooks
event_webhook_sign(event_webhook_id: str, enabled: bool) -> strEnable/disable signature verification, returns public key

Data Structures #

Settings #

Configuration for the EmailClient.

FieldTypeDescription
keystrSendGrid API key

Address #

Represents an email address with display name.

FieldTypeDescription
emailstrEmail address
namestrDisplay name

Recipient #

Represents an email recipient with type.

FieldTypeDescription
addressAddressEmail address object
typeRecipientTypeTO, CC, or BCC

BodyContent #

Represents email body content with MIME type.

FieldTypeDescription
typestrMIME type (e.g., text/plain, text/html)
valuestrContent

Email #

Complete email message structure.

FieldTypeDescription
senderAddressSender email address
reply_toslist[Address]Reply-to addresses
recipientslist[Recipient]List of recipients (TO/CC/BCC)
subjectstrEmail subject line
bodieslist[BodyContent]Email body content(s)
attachmentslist[Attachment]File attachments
send_atintUnix timestamp for sending

Class Methods:

MethodDescription
Email.now() -> intGet current timestamp for immediate send
Email.timestamp(dt: datetime) -> intConvert datetime to Unix timestamp

Attachment #

Represents an email attachment.

FieldTypeDescription
content_idstrID for inline references
contentstrBase64 encoded content
typestrMIME type
filenamestrFilename
dispositionAttachmentDispositionATTACHMENT or INLINE

Class Methods:

MethodDescription
Attachment.from_url(url, headers, filename) -> AttachmentCreate attachment from URL
Attachment.from_url_inline(url, headers, filename, content_id) -> AttachmentCreate inline attachment from URL

LoggedEmailCriteria #

Search criteria for querying sent emails.

FieldTypeDescription
message_idstrFilter by message ID
subjectstrFilter by subject
to_emailstrFilter by recipient email
reasonstrFilter by reason
statuslist[StatusEmail]Filter by status(es)
message_created_atlist[CriterionDatetime]Filter by creation date/time

CriterionDatetime #

DateTime comparison for email queries.

FieldTypeDescription
date_timedatetimeDate/time to compare
operationCriterionOperationComparison operator

SentEmail #

Basic information about a sent email (returned by logged_emails).

FieldTypeDescription
from_emailstrSender email address
message_idstrSendGrid message ID
subjectstrEmail subject
to_emailstrRecipient email address
reasonstrDelivery failure reason
statusStatusEmailDelivery status
created_atdatetimeCreation timestamp

SentEmailDetail #

Detailed sent email information with event history (returned by logged_email).

FieldTypeDescription
from_emailstrSender email address
message_idstrSendGrid message ID
subjectstrEmail subject
to_emailstrRecipient email address
statusStatusEmailCurrent delivery status
eventslist[EmailEvent]List of lifecycle events

EmailEvent #

Represents an event in an email’s lifecycle.

FieldTypeDescription
eventEventEmailEvent type
emailstrRecipient email address
message_idstrSendGrid message ID
event_idstrUnique event ID
on_datetimedatetimeEvent timestamp
reasonstrReason (for bounce, dropped events)
responsestrServer response (for delivered events)
urlstrClicked/opened URL (for click, open)
attemptintDelivery attempt number (for deferred)

ParseSetting #

Configuration for inbound email parsing.

FieldTypeDescription
urlstrWebhook URL to receive parsed emails
hostnamestrDomain to receive emails (requires MX record)
spam_checkboolEnable spam filtering
send_rawboolSend raw MIME message instead of parsed

EventWebhook #

Configuration for outbound email event notifications.

FieldTypeDescription
enabledboolWhether webhook is active
urlstrWebhook URL
friendly_namestrDisplay name
deliveredboolTrack delivered events
bounceboolTrack bounce events
droppedboolTrack dropped events
spam_reportboolTrack spam report events
processedboolTrack processed events
openboolTrack open events
clickboolTrack click events
unsubscribeboolTrack unsubscribe events
group_resubscribeboolTrack group resubscribe events
group_unsubscribeboolTrack group unsubscribe events

EventWebhookRecord #

Stored event webhook with metadata (extends EventWebhook).

FieldTypeDescription
(all fields from EventWebhook)  
idstrWebhook ID
public_keystrPublic key for signature verification
created_datedatetimeCreation timestamp
updated_datedatetimeLast update timestamp

ParsedEmail #

Represents an inbound email received via the Inbound Parse webhook.

FieldTypeDescription
headerslist[ParsedHeader]Email headers
charsetsdict[str, str]Character set mappings
envelopeParsedEnvelopeSMTP envelope information
email_fromstrSender address
email_tostrRecipient address
subjectstrEmail subject
textstrPlain text body
htmlstrHTML body
attachmentsintNumber of attachments
attachment_infodict[str, ParsedAttachment]Attachment metadata
content_idsdict[str, str]Content ID mappings
spfstrSPF verification result
dkimstrDKIM verification result
spam_reportlist[str]Spam analysis report
spam_scorefloatSpam score

Constants (Enums) #

RecipientType #

ValueDescription
TOPrimary recipient
CCCarbon copy
BCCBlind carbon copy

AttachmentDisposition #

ValueDescription
ATTACHMENTStandard file attachment
INLINEEmbedded in email body

StatusEmail #

Email delivery status values.

ValueDescription
PROCESSEDEmail processed by SendGrid
DELIVEREDSuccessfully delivered
NOT_DELIVEREDDelivery failed
DEFERREDTemporarily delayed
DROPPEDDropped by SendGrid
BOUNCEDBounced back
BLOCKEDBlocked by recipient

EventEmail #

Email event types for webhooks.

ValueDescription
BOUNCEEmail bounced
CLICKLink clicked
DEFERREDDelivery deferred
DELIVEREDEmail delivered
DROPPEDEmail dropped
CANCEL_DROPDrop cancelled
OPENEmail opened
PROCESSEDEmail processed
RECEIVEDInbound email received
SPAM_REPORTReported as spam
GROUP_UNSUBSCRIBEUnsubscribed from group
GROUP_RESUBSCRIBEResubscribed to group
UNSUBSCRIBEUnsubscribed

CriterionOperation #

Comparison operators for email log queries.

ValueSymbolDescription
GREATER_THAN>Greater than
GREATER_THAN_OR_EQUAL>=Greater than or equal
LOWER_THAN<Less than
LOWER_THAN_OR_EQUAL<=Less than or equal
EQUAL=Equal to

Error Handling #

RequestFailed #

Exception raised when a SendGrid API request fails (extends RuntimeError).

AttributeTypeDescription
status_codeintHTTP status code
messagestrError message from SendGrid

Example:

try:
    client.simple_send(email)
except RequestFailed as e:
    print(f"Error {e.status_code}: {e.message}")

Webhook Setup Examples #

Inbound Parse Webhook (Receive Incoming Emails) #

from canvas_sdk.clients.sendgrid.structures import ParseSetting

# Note: Requires MX record for the hostname pointing to mx.sendgrid.net
setting = ParseSetting(
    url="https://your-app.com/api/incoming-email",
    hostname="mail.yourdomain.com",
    spam_check=True,
    send_raw=False,
)

try:
    created = client.parser_setting_add(setting)
    print(f"Inbound webhook created for {created.hostname}")
except RequestFailed as e:
    print(f"Failed: {e.message}")

Event Webhook (Track Outbound Email Status) #

from canvas_sdk.clients.sendgrid.structures import EventWebhook

webhook = EventWebhook(
    url="https://your-app.com/api/email-events",
    enabled=True,
    friendly_name="My Email Tracker",
    delivered=True,
    bounce=True,
    dropped=True,
    spam_report=True,
    processed=True,
    open=True,
    click=True,
    unsubscribe=False,
    group_resubscribe=False,
    group_unsubscribe=False,
)

try:
    created = client.event_webhook_add(webhook)
    print(f"Event webhook created with ID: {created.id}")
except RequestFailed as e:
    print(f"Failed: {e.message}")

Additional Resources #