Skip to content

Releases: mailtea-app/mailtea-python

v0.23.0

Choose a tag to compare

@davepoon davepoon released this 16 Oct 12:08
  • Changed (API): emails.inbound.reply passes to and headers through as it always did, but the API now acts on them instead of dropping them: a to naming anyone the original did not carry raises on a 422 reply_target_not_allowed, and any header other than Auto-Submitted and X-Auto-Response-Suppress raises on a 400. The docstring documents both and the plan-limit code values.
  • Added: api_keys.current() describes the calling key.
  • Changed (docs): emails.inbound.reply documents attachments; emails.get documents message_id; emails.inbound.get documents the arrival checks. The fields already passed through.

Released from mailtea-app/mailtea@615cef4.

v0.22.0

Choose a tag to compare

@davepoon davepoon released this 14 Oct 12:12
  • Changed (API): posts.send, and posts.create with send=True, send to
    the whole audience. They used to stop at 10,000 recipients without saying
    so. One send can reach at most 25,000; a larger audience raises on a 422
    audience_too_large that carries audience_count and max_recipients,
    and nothing is sent or scheduled. On posts.create the error body carries
    the draft's id. A send also raises on a 409 post_changed when the post
    was scheduled or edited elsewhere while the request was preparing it. No
    package change: this is the API's behaviour once it is deployed.

Released from mailtea-app/mailtea@1d368b5.

v0.21.0

Choose a tag to compare

@davepoon davepoon released this 03 Oct 06:47
  • Changed (API): posts.send, and posts.create with send=True, now raise
    on a 403 system_domain_recipient_restricted (with restriction) when the
    team has no verified sending domain and the audience includes anyone outside
    the team, or the post sends from the built-in *.mailtea.email address.
    Nothing is sent or scheduled and the post stays a draft; on posts.create
    the error body carries the draft's id. The send used to be accepted and
    fail a moment later. A broadcast (kind="broadcast") is never published to
    the website, however it is sent. No package change: this is the API's
    behaviour once it is deployed.

Released from mailtea-app/mailtea@68b43c2.

v0.20.0

Choose a tag to compare

@davepoon davepoon released this 01 Oct 09:04
  • Changed (API): contacts.list(search=...) with several whole addresses
    separated by commas or spaces now returns exactly those contacts (up to
    200), the same as Mailtea Studio and MCP. A list with an entry that is not
    a whole address is refused with a 400 naming it. Part of an address still
    matches as before. The docstring says so.
  • Added: purpose on domains.claims.create ("email", "site" or "both",
    default "email") and on every claim reply. A site claim gets no sending
    identity. The package passes it through as it is; this release documents it.
    Needs the API deployed with this change.
  • Added: segment_id on posts.create and posts.update (None clears it
    on update) and on every post reply, to send a post to one segment of its
    publication instead of all active contacts. inactive_days on
    segments.create and segments.update (None clears it) and on every
    segment reply: contacts with no open or click in the last N days (1 to
    3650), counting contacts who never engaged, which is the silent cohort and
    not engaged readers. The package passes both through as it is; this release
    documents them. They need the API deployed with this change.
  • Changed: segments.delete documents that a segment a draft, scheduled or
    sending post targets cannot be deleted: it raises MailteaError with
    status 409 and code segment_in_use. Deleting one used to send those
    posts to everyone.

Released from mailtea-app/mailtea@1ea0e1b.

v0.19.0

Choose a tag to compare

@davepoon davepoon released this 29 Sep 02:33
  • Changed: template history records the sender. Each entry from
    templates.versions() carries from (read it as entry["from"]),
    reply_to and sender_recorded, an update that changes only the From or
    Reply-To records a version (or folds into the open one, like any edit), and
    templates.restore_version() brings the version's From and Reply-To back
    with the design. A version with sender_recorded False was recorded
    before this change and leaves the current From and Reply-To alone when
    restored. The behaviour comes from the API and reaches every package version
    on deploy; this release updates the docstrings.

Released from mailtea-app/mailtea@ff8e7ef.

v0.18.0

Choose a tag to compare

@davepoon davepoon released this 28 Sep 02:45
  • Added: optimistic-concurrency tokens for editing over an API that may also
    be edited in Mailtea Studio or by another agent. templates.update and
    templates.publish accept base_revision (read from a template's
    revision, now on every template reply); a stale value answers with
    MailteaError (code stale_write, the response body also carrying
    current_revision) and nothing is saved. automations.update accepts
    base_version the same way for graph writes (steps), answering code
    stale_version. posts.update accepts base_updated_at (read from a
    post's updated_at, now also returned by posts.update itself), answering
    code stale_write with current_updated_at. All three are optional;
    omit them for today's unconditional write.

  • Changed: posts.create / posts.update keep the from (keyword from_=)
    and reply_to you pass, and posts.get returns them (None when the named
    sender or the publication default decides). name is only the post's
    internal name and no longer overwrites the subject. posts.update changes
    only the fields you pass; "" clears name, from or reply_to.

  • Note: a from that is not on one of the publication's verified sending
    domains is refused with a 422, and reply_to must be a valid address.

  • Docs: automations.activate lists the two cloud-only no_verified_sender
    reasons, CUSTOM_DOMAIN_REQUIRED and the new BUILT_IN_SENDER (a step sends
    from the built-in {slug}.mailtea.email address). No runtime change.

  • Breaking: posts.create() with template_id now HTML-escapes the
    variables you pass, the same as every other send. HTML passed in a
    {{key}} value now arrives as visible text, and a value you escaped
    yourself arrives double-escaped. Put {{{key}}} in the template where a
    value is meant to be raw HTML. Variables are now filled in both the
    {{key}} and Visual Email Designer {key} forms. A declared variable you
    do not pass stays in the post with its fallback_value, so the broadcast
    gives each recipient their own value or that fallback, and undeclared tokens
    like {{contact.first_name}} are left for the broadcast too. The post keeps
    the template's published page style, is wrapped in that page, and has its
    show-if blocks decided per recipient when it is sent. Before, only the
    variables you passed were replaced, raw, and only in {{key}} form. It uses
    the template's published version; Mailtea Studio's "Use template" starts
    from the latest saved design instead.

  • Changed: templates.update() and templates.restore_version() no longer
    move a published template back to draft. The template keeps its published
    status, and automations and the API keep sending its published version until
    templates.publish() is called again. The template's from and reply_to
    are part of the published version too, so a new sender or reply-to address
    reaches sends only after the next publish. templates.unpublish() is now
    the only way to stop a published template sending, short of deleting it, and
    it drops the stored published version so the next publish starts from the
    current content.

  • Added: has_unpublished_versions on every returned template. True only when
    the template is published and its saved content (From, Reply-To and the
    style profile included) differs from the published version.

  • Added: is_published on each template version entry: true for the one entry
    automations and the API are sending now. is_current is now described as
    what it is: the entry that matches the working copy (the saved design being
    edited), not necessarily what is sending. is_published is false on every
    entry of a draft, and on a template published before the field existed until
    it is published again.

  • Changed: the unpublished field on the update and restore replies is kept
    for compatibility and is now always False. Check
    has_unpublished_versions (or the reply's message) instead.

  • Changed (API behavior): a template variable's fallback_value can no longer
    contain { or }. Creating a template with one, or changing a fallback
    to one on update, is a 400 ("Fallbacks can't contain { or }."). A value
    the template already stores is accepted unchanged, so a template saved
    before the rule keeps saving. Inline chip fallbacks such as
    {first_name|Mom & Pop} now render as written instead of double-escaped.

  • Changed (API behavior): saving an active automation is refused only when the
    edit adds an error the live version does not already have. The 422
    active_graph_invalid reply's issues lists just those new problems.
    Before, any error refused the save, even one the live version already had.
    Starting refuses every error as before, except an unknown_step_ref at a
    config.* path or a trigger missing_branch that the version the
    automation last ran on already had, so pausing and starting an unchanged
    automation keeps working. Issues the last live version already had come back
    with pre_existing: true.

  • Added (API behavior): issue objects carry field, what a rule reads (the
    rule's field, or the path in a {"var": ...} value, e.g.
    steps.welcome.opened) when the issue is about one.

  • Changed (API behavior): two issues are the same problem when their code and
    step match, and their field or, when there is none, their path. Moving
    a rule, by removing a rule beside it or putting it in a group, no longer
    makes a problem the live version already had look new. An error is
    pre_existing only if the live version had an error there, not a warning.

  • Changed (API behavior): validate_only on an active automation answers the
    way the save would. A trigger change is a 422 trigger_locked_while_active,
    a change that adds a problem is a 422 active_graph_invalid listing only
    the new problems, and otherwise issues come back with pre_existing marked
    against the version live now. Before, it returned every issue unmarked.

  • Changed (API behavior): changing the trigger (its type or key) of an active
    automation is now refused with 422 trigger_locked_while_active. Pause it
    first; draft and paused automations can still change their trigger. Before,
    the change was accepted.

  • Added (API behavior): new validation rules. A trigger with nothing after it
    is a missing_branch error at branches.next. A rule or {"var": ...}
    value that reads steps.<key>.* for a step that isn't in the automation is
    an unknown_step_ref error at that config.* path, or a warning when the
    {"var": ...} has a default. A rule or value that reads
    event.properties.* when the automation does not start from an app event is
    the new warning event_field_without_event_trigger.

  • Changed (API, no client change needed): emails.send(template=...) may
    leave out subject, from_ and sender_id. The template's published
    subject is used, and its sender is the publication's default sender, then
    the template's own From. The send docstring now says so.

  • Behaviour (API): the template's variables fill the subject with the same
    values and fallbacks as the body.


Released from mailtea-app/mailtea@acea165.

v0.12.0

Choose a tag to compare

@davepoon davepoon released this 15 Sep 11:33
  • Added: test mode. api_keys.create(name=..., mode="test") mints a test key
    (prefixed mt_test_) whose sends are validated, recorded and webhook-emitting
    but never delivered, so CI can run against production Mailtea with your real
    code and your real webhook handler. A test key is not a data sandbox — it
    reads and writes your real contacts, templates, senders and webhooks. Only
    delivery is simulated.
  • Added: emails.list(mode="test") reads test-mode mail, and every email
    carries mode. There is no mixed view: a test key reads only test emails and
    a live key only live ones.
  • Reserved recipients on test.mailtea.email force an outcome: delivered@,
    bounced@, complained@, delayed@, failed@. The first to recipient
    decides; anything else is delivered.
  • Note: mode is never accepted on a send. The key decides.

Released from mailtea-app/mailtea@8c362fb.

v0.11.0

Choose a tag to compare

@davepoon davepoon released this 10 Sep 21:41
  • Changed: automations.activate() documents the no_verified_sender refusal.
    A 422 with that code means a send_email step has no sender it can send
    from; reason (NO_SENDER, DOMAIN_NOT_VERIFIED, WRONG_PURPOSE,
    DKIM_NOT_VERIFIED or INVALID_FROM) says which, and steps[] names every
    blocking step. Previously only automation_invalid was documented.
  • Added: domains.update(id, tracking_subdomain=None) removes a tracking
    subdomain. The domain's links go back to being served from the Mailtea host.
    Links in mail you have already sent point at the old hostname and stop
    resolving — there is no way to reinstate them. The None reaches the wire as
    an explicit null, so omitting the key and passing None are different
    requests. An empty string is neither: it is refused with
    tracking_subdomain_invalid.
  • Changed: the MX row in records now reports what the last verify found,
    instead of reading pending on every request but the verify itself. A domain
    nobody has verified reads not_started.

Released from mailtea-app/mailtea@fed0718.

v0.10.0

Choose a tag to compare

@davepoon davepoon released this 05 Sep 01:00
  • Added: domains.claims — create(), get(), verify() and cancel(). When
    adding a domain is refused with code domain_held_elsewhere, another
    publication holds the host; publish one TXT record to prove you control its
    DNS and the domain moves to you.

  • Documented: domains.create() takes region (fixed at creation), tls and
    tracking_subdomain, and domains.list() filters on region and status.
    The resource forwards whatever you pass, so these worked already — this
    release is where they are stated and covered by tests.

  • Added: contacts.set_property_values() and contacts.list_property_values().
    These write and read the per-contact values behind {{contact.<key>}} merge
    tags — previously only possible from the dashboard, so a script could define a
    property and never fill it in. Identify each value by key (the name in your
    template) or property_id, not both; an empty value clears it and restores
    the property's fallback_value.

  • Documented: assets.upload accepts SVG (image/svg+xml); the docstring said it
    was refused. The API has accepted it, served under a sandboxing CSP, since the
    asset library shipped. Docs-only, no behaviour change.


Released from mailtea-app/mailtea@1dff0ba.

v0.9.1

Choose a tag to compare

@davepoon davepoon released this 25 Aug 12:06
  • Documented: the API now enforces your plan's analytics retention window on
    from_date. It is clamped to 30 days on most plans and 90 on Scale and
    Enterprise; a value reaching further back returns data from the start of that
    window rather than an error, and omitting it returns the window rather than
    all time. No code change is required — this release only makes the behaviour
    visible where you read it.
  • Changed: the list and analytics responses now report the window actually used
    in from_date, so a clamped request is visible rather than silently short.
  • Changed: emails.list() and emails.analytics() docstrings carry it.

Released from mailtea-app/mailtea@c311c79.