Skip to main content

densend

The official Python client for DenSend.

pip install densend

Requires Python 3.8 or newer.

Sending

import densend

densend.api_key = "your DENSEND_API_KEY"

email = densend.Emails.send({
    "from": "You <hello@yourdomain.com>",
    "to": "someone@example.com",
    "subject": "Hello from DenSend",
    "html": "<p>Your order has shipped.</p>",
})
print(email["id"])

from has to be on a domain you have added and verified.

densend.api_key also reads from the DENSEND_API_KEY environment variable, so setting it explicitly is only needed when you want to override that.

Multiple recipients get one id each, because a bounce belongs to exactly one address:

email = densend.Emails.send({
    "from": "You <hello@yourdomain.com>",
    "to": ["first@example.com", "second@example.com"],
    "cc": ["copied@example.com"],
    "reply_to": "support@yourdomain.com",
    "subject": "Your receipt",
    "text": "Thanks for your order.",
})
print(email["ids"])

Scheduling

Pass a datetime or an ISO 8601 string. Anything in the past sends immediately.

from datetime import datetime, timedelta, timezone

densend.Emails.send({
    "from": "You <hello@yourdomain.com>",
    "to": "someone@example.com",
    "subject": "A reminder",
    "text": "This was scheduled.",
    "scheduled_at": datetime.now(timezone.utc) + timedelta(hours=1),
})

Attachments

with open("invoice.pdf", "rb") as f:
    content = f.read()

densend.Emails.send({
    "from": "You <hello@yourdomain.com>",
    "to": "someone@example.com",
    "subject": "Your invoice",
    "text": "Attached.",
    "attachments": [
        {"filename": "invoice.pdf", "content": content, "content_type": "application/pdf"},
    ],
})

content can be bytes (encoded automatically) or a str you have already base64-encoded yourself. 7MB total across all attachments, combined. Going over raises a DenSendError naming the actual size, not a generic failure.

Reading

email = densend.Emails.get(email_id)
print(email["status"], email["opens"], email["clicks"])

recent = densend.Emails.list(limit=20)

Errors

Every non-2xx response raises a DenSendError carrying the status, so you can tell a bad key from a spent quota without parsing strings.

from densend import DenSendError

try:
    densend.Emails.send({...})
except DenSendError as error:
    if error.status == 401:
        raise RuntimeError("Check DENSEND_API_KEY") from error
    if error.is_retryable:
        queue_for_later()
    else:
        raise

is_retryable is true for 429 and 5xx. A 422 means the payload was wrong and retrying it unchanged will fail the same way.

Options

densend.base_url = "https://api.densend.com/v1"  # override when self-hosting

base_url also reads from the DENSEND_BASE_URL environment variable.

Sending is asynchronous

send returns once DenSend has accepted the message, not once it has landed. The returned id is how you follow it afterwards, through Emails.get or a webhook.

Download files

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

Source Distribution

densend-0.1.0.tar.gz (6.3 kB view details)

Uploaded Source

Built Distribution

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

densend-0.1.0-py3-none-any.whl (6.9 kB view details)

Uploaded Python 3

File details

Details for the file densend-0.1.0.tar.gz.

File metadata

  • Download URL: densend-0.1.0.tar.gz
  • Upload date:
  • Size: 6.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for densend-0.1.0.tar.gz
Algorithm Hash digest
SHA256 7bde71f9ec584e6b2aa8e9be35737d34d599d789e90b9ceeb1eed9589849d608
MD5 5865271efa893c5b08dac4359123443d
BLAKE2b-256 8df98929f510362a9ce808a441ff1903832f4ca25f9ec0c05480ce83fb9640ff

See more details on using hashes here.

File details

Details for the file densend-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: densend-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 6.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for densend-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 469fd0f575ff8f6dd50aa639a362cc8338fdee929c71ace0709da60309289c58
MD5 ad5659ccd1cb2099d6cfe1bbfc8aef22
BLAKE2b-256 bde70c51b8fb10d5865f2a1c8e5f82f6e47712bc37bcaf7714d9caf8278dfd55

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page