Skip to main content

Sidemail Python library for email sending and API

Project description

Sidemail Python Library

Official Sidemail.io Python library providing convenient access to the Sidemail API from Python applications.

Requirements

  • Python 3.8+

Installation

pip install sidemail

Usage

First, the package needs to be configured with your project's API key, which you can find in the Sidemail Dashboard after you signed up.

from sidemail import Sidemail
sm = Sidemail(api_key="xxxxx") # or set SIDEMAIL_API_KEY env var

resp = sm.send_email(
  toAddress="user@email.com",
  fromAddress="you@example.com",
  fromName="Your App",
  templateName="Welcome",
  templateProps={"foo": "bar"},
)

print(f"Email sent! ID: {resp.id}")

The response looks like:

{
  "id": "5e858953daf20f3aac50a3da",
  "status": "queued"
}

Shortcut sm.send_email(...) calls sm.email.send(...) under the hood.

Authentication

Explicit key:

from sidemail import Sidemail
sm = Sidemail(api_key="your-api-key")

Or if you set environment variable SIDEMAIL_API_KEY, then simply:

from sidemail import Sidemail
sm = Sidemail() # reads SIDEMAIL_API_KEY

Client configuration

import httpx
from sidemail import Sidemail

sm = Sidemail(
	api_key="your-api-key",
	base_url="https://api.sidemail.io/v1", # override for testing/mocking
	timeout=10.0,  # per-request timeout (seconds)
	session=httpx.Client(), # custom httpx.Client (proxies, retries, etc.)
)

Email Sending Examples

Password reset template

sm.send_email(
	toAddress="user@email.com",
	fromAddress="you@example.com",
	fromName="Your App",
	templateName="Password reset",
	templateProps={"resetUrl": "https://your.app/reset?token=123"},
)

Schedule email delivery

import datetime

scheduled_iso = (datetime.datetime.utcnow() + datetime.timedelta(minutes=60)).isoformat() + "Z"
sm.send_email(
	toAddress="user@email.com",
	fromAddress="your@startup.com",
	fromName="Startup name",
	templateName="Welcome",
	templateProps={"firstName": "Patrik"},
	scheduledAt=scheduled_iso,
)

Template with dynamic list

sm.send_email(
	toAddress="user@email.com",
	fromAddress="your@startup.com",
	fromName="Startup name",
	templateName="Template with dynamic list",
	templateProps={
		"list": [
			{"text": "Dynamic list"},
			{"text": "allows you to generate email template content"},
			{"text": "based on template props."},
		]
	},
)

Custom HTML email

sm.send_email(
	toAddress="user@email.com",
	fromAddress="your@startup.com",
	fromName="Startup name",
	subject="Testing html only custom emails :)",
	html="<html><body><h1>Hello world! 👋</h1></body></html>",
)

Custom plain text email

sm.send_email(
	toAddress="user@email.com",
	fromAddress="your@startup.com",
	fromName="Startup name",
	subject="Testing plain-text only custom emails :)",
	text="Hello world! 👋",
)

Error handling

The SDK throws SidemailError for all errors. API errors include message, httpStatus, errorCode, and moreInfo.

from sidemail import Sidemail, SidemailError

sm = Sidemail(api_key="your-api-key")
try:
	sm.send_email(
		toAddress="user@example.com",
		fromAddress="you@example.com",
		subject="Hello",
		text="Hello",
	)
except SidemailError as e:
	print(e.message)
	if e.httpStatus:  # API error
		print(e.httpStatus, e.errorCode, e.moreInfo)

Response objects

Most responses are wrapped in a Resource enabling attribute access while remaining dict-like.

  • Field names that collide with Python keywords or are invalid identifiers are suffixed with _.
  • Methods return Resource wrappers (attribute + dict access); unwrap via .to_dict().
  • Original JSON available via .raw.
email = sm.email.get("email-id")
print(email.id, email.status)
print(email["id"])          # dict-style
raw_json = email.raw         # original JSON mapping
flat_dict = email.to_dict()  # fully unwrapped dict

Attachments helper

from sidemail import Sidemail

with open("invoice.pdf", "rb") as f:
  attachment = Sidemail.file_to_attachment("invoice.pdf", f.read())

  sm.send_email(
    toAddress="user@email.com",
    fromAddress="you@example.com",
    subject="Invoice",
    text="Invoice attached.",
    attachments=[attachment],
  )

Auto-pagination

List/search methods return a QueryResult containing the first page in result.data. Iterate across all pages with auto_paginate().

result = sm.contacts.list(limit=50)

for contact in result.auto_paginate():
	print(contact.emailAddress)

Callback-style iteration can be created easily with a helper (not built-in); use the for-loop above.

Supported auto-paging methods:

  • sm.contacts.list()
  • sm.contacts.query()
  • sm.email.search()
  • sm.messenger.list()

Email Methods

Search emails

Paginated (supports auto-pagination).

result = sm.email.search(
	query={
		"toAddress": "john.doe@example.com",
		"status": "delivered",
		"templateProps": {"foo": "bar"},
	},
	limit=50,
)

print("First page count:", len(result.data))
for email in result.auto_paginate():
	print(email.id, email.status)

Retrieve a specific email

email = sm.email.get("SIDEMAIL_EMAIL_ID")
print("Email status:", email.status)

Delete a scheduled email

Only scheduled (future) emails can be deleted.

resp = sm.email.delete("SIDEMAIL_EMAIL_ID")
print("Deleted:", getattr(resp, "deleted", resp))

Contact Methods

Create or update a contact

contact = sm.contacts.create_or_update(
	emailAddress="marry@lightning.com",
	identifier="123",
	customProps={
		"name": "Marry Lightning",
		# ... more props ...
	},
)
print("Contact status:", contact.status)

Find a contact

contact = sm.contacts.find("marry@lightning.com")
if contact:
	print("Found contact:", contact.emailAddress)

List all contacts

result = sm.contacts.list(limit=50)
print("Has more:", result.hasMore)
for c in result.auto_paginate():
	print(c.emailAddress)

Query contacts (filtering)

result = sm.contacts.query(limit=100, query={"customProps.plan": "pro"})
for c in result.auto_paginate():
	print(c.emailAddress)

Delete a contact

resp = sm.contacts.delete("marry@lightning.com")
print(resp)

Project Methods

Linked projects are associated with the parent project of the API key used to initialize Sidemail. After creation, update the design to personalize templates.

Create a linked project

project = sm.project.create(name="Customer X linked project")
# Important! Save project.apiKey for later use

Update a linked project

updated = sm.project.update(
	name="New name",
	emailTemplateDesign={
		"logo": {
			"sizeWidth": 50,
			"href": "https://example.com",
			"file": "PHN2ZyBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGZpbGwtcnVsZT0iZXZlbm9kZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLW1pdGVybGltaXQ9IjIiIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJtMTIgNS43MmMtMi42MjQtNC41MTctMTAtMy4xOTgtMTAgMi40NjEgMCAzLjcyNSA0LjM0NSA3LjcyNyA5LjMwMyAxMi41NC4xOTQuMTg5LjQ0Ni4yODMuNjk3LjI4M3MuNTAzLS4wOTQuNjk3LS4yODNjNC45NzctNC44MzEgOS4zMDMtOC44MTQgOS4zMDMtMTIuNTQgMC01LjY3OC03LjM5Ni02Ljk0NC0xMC0yLjQ2MXoiIGZpbGwtcnVsZT0ibm9uemVybyIvPjwvc3ZnPg==",
		},
		"font": {"name": "Acme"},
		"colors": {"highlight": "#0000FF", "isDarkModeEnabled": True},
		"unsubscribeText": "Darse de baja",
		"footerTextTransactional": "You're receiving these emails because you registered for Acme Inc.",
	},
)

Get a project

project = sm.project.get()
print(project.id, project.name)

Delete a linked project

resp = sm.project.delete()
print(resp)

Messenger API (newsletters)

result = sm.messenger.list(limit=20)
for m in result.auto_paginate():
	print(m.id, m.get("name"))

messenger = sm.messenger.get("messenger-id")
created = sm.messenger.create(subject="My Messenger", markdown="Broadcast message...")
updated = sm.messenger.update("messenger-id", name="Updated name")
deleted = sm.messenger.delete("messenger-id")

Sending domains API

domains = sm.domains.list()
domain = sm.domains.create(name="example.com")
deleted = sm.domains.delete("domain-id")

More Info

Visit Sidemail docs for more information.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sidemail-0.1.2.tar.gz (11.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sidemail-0.1.2-py3-none-any.whl (8.4 kB view details)

Uploaded Python 3

File details

Details for the file sidemail-0.1.2.tar.gz.

File metadata

  • Download URL: sidemail-0.1.2.tar.gz
  • Upload date:
  • Size: 11.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for sidemail-0.1.2.tar.gz
Algorithm Hash digest
SHA256 7ead4412bad1a6a2b8e6fda72e5a8cf9219bcc195fc4e5420e8558d70498a777
MD5 a8d82c92263bd72a5d5b76607cf4ccf0
BLAKE2b-256 d5d27ccf3b2f2b9fd4da691824955934ea8a02468afcfe6746480c56af741866

See more details on using hashes here.

Provenance

The following attestation bundles were made for sidemail-0.1.2.tar.gz:

Publisher: publish.yml on sidemail/sidemail-sdk-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file sidemail-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: sidemail-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 8.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for sidemail-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 eab06f9b2888b1e1abb5f44880ce3c0a6e3bf1404432b094f7676d5e76498faf
MD5 00189d282304d55dbc2c28a77749c456
BLAKE2b-256 c17b586888bbf92034344936075c7a6d3d55cfdb28b1bfd2cdb981dbaa0d2d14

See more details on using hashes here.

Provenance

The following attestation bundles were made for sidemail-0.1.2-py3-none-any.whl:

Publisher: publish.yml on sidemail/sidemail-sdk-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page