Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,24 @@
All notable changes to `sendly-python` are documented here. This project adheres to
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added

- **`emails.send` takes `listUnsubscribe`**, the https URL of your own one-click
unsubscribe endpoint. A transactional send carries no unsubscribe of Sendly's,
because Sendly cannot know what the reader would be opting out of; with this
field Sendly writes `List-Unsubscribe: <url>` and
`List-Unsubscribe-Post: List-Unsubscribe=One-Click` (RFC 8058), so the mail
client shows its own unsubscribe button. The two headers stay reserved in
`headers`. The server answers `422` for a value that is not https, is over
2048 characters, or contains whitespace, a comma or angle brackets. Campaign
and workflow sends ignore it and keep Sendly's own link.
- **The vendored spec is re-synced** from the platform contract. The new mailbox
conversation and domain-logo operations are listed as not yet implemented, and
the provider compat dialects under `/api/compat/` are excluded by path: those
are for the other providers' own SDKs.

## [1.1.0] - 2026-09-05

Four new resources, the `/api/v1` half of six that only had a legacy one, and a
Expand Down
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,13 @@ receipt = sendly.emails.send({"from": "a@you.com", "to": "b@them.com", "subject"
sendly.emails.send_legacy({"from": "a@you.com", "to": ["b@them.com", "c@them.com"],
"subject": "Hi", "body": "<p>Hi</p>"})

# Your own one-click unsubscribe (https only). Sendly writes the RFC 8058
# List-Unsubscribe headers, so the mail client shows its unsubscribe button; the
# endpoint gets a cookie-less POST and must unsubscribe the reader on it alone.
sendly.emails.send({"from": "notify@you.com", "to": "b@them.com", "subject": "New reply",
"body": "<p>Someone replied.</p>",
"listUnsubscribe": "https://you.com/unsubscribe?token=abc123"})

# Batch send (up to 100)
sendly.emails.batch({"emails": [{"from": "a@you.com", "to": "b@them.com", "subject": "Hi", "body": "<p>Hi</p>"}]})

Expand Down
Loading
Loading