Skip to the documentation
Python

Changelog

Every release of the package, newest first.

0.0.3

The third release adds the 73 methods the TypeScript SDK gained since 0.0.2, so it covers all 558 again.

  • threads.mute and threads.unmute mute a conversation and take the mute off, as Mute does in the app, and both need threads:write. A muted thread in the inbox moves to the archive, and new mail in it goes straight to the archive, unread, with no push, sound or desktop notification. Muting is for the whole workspace, a muted thread carries the built-in MUTE label, and is:muted finds it in query.
  • The inbox has tabs: Primary, Promotions, Updates, Social and Forums. threads.list, list_all and iterate take category= to read one tab, and category:promotions filters the same way in query. threads.counts returns categories, the conversations and unread conversations of the inbox in each tab.
  • threads.list_sender_categories, set_sender_category and clear_sender_category manage the senders whose mail always goes to one tab, whatever the sorting rules would say. Saving a choice also moves the inbox threads whose newest message is from that sender, up to the newest 1,000. A key limited to particular addresses or domains can read the choices but not change them.
  • The new follow_ups namespace holds the reminders on mail you sent: set asks for a thread to come back to the top of the inbox, unread, with the built-in FOLLOW_UP label and a push, if nobody replies by remindAt, list reads the reminders still waiting and the ones that ended, and cancel cancels one. A real reply closes the reminder by itself, and a thread holds one waiting reminder per person, so setting another moves the time. emails.send and each message of emails.send_batch take followUpAt to set a reminder as the message goes out: a datetime, an ISO 8601 instant or a duration such as P3D.
  • The new out_of_office namespace manages the automatic reply an address sends while its owner is away. set saves the reply of one address, or of a catch-all with *@example.com, with its message, subject, start, end and contactsOnly, list reads every reply saved in the workspace, and clear removes one. While a reply is active, each person who writes gets the message once for the whole away period, and spam, bulk mail, automatic mail and bounces get no reply.
  • Labels can be applied by AI: labels.create and labels.update take aiInstructions, what the label is for in plain words, and aiEnabled, which has AI read each arriving message against them and add the label when it fits. It only labels and never archives or moves mail, turning it on needs instructions and a paid plan, and a workspace may have 10 such labels. labels.test runs the AI over the newest 20 inbox threads and returns the ones the label would catch, without labelling anything, and spends one AI action.
  • settings.get and settings.update carry three more account settings: inboxTabs shows the inbox as tabs, primaryOnlyAlerts keeps pushes, sounds and desktop notifications to mail sorted into Primary while tabs are on, and phoneFollowUps sends a push when a reminder comes due.
  • Mail travels in two lanes, so a newsletter cannot hold up or harm app mail. emails.send, each message of emails.send_batch and templates.send take stream: transactional, the default, for mail one person is waiting for, or broadcast for newsletters. Every email carries the stream it went out on, and every copy of a broadcast is on the broadcast lane.
  • The new sending namespace reads the lanes: list_streams returns both with their state and their numbers for the last 7 days, which are recipients, bounces, complaints and the two rates. The broadcast lane pauses itself above 4% bounces or 0.2% complaints, a send to it is then refused with 409 stream_paused, and app mail keeps going. resume_stream resumes it, for the workspace owner, and asks an app for a verification code.
  • tools.check_address says whether an address is worth sending to before the first message: valid, risky, invalid or unknown, with the reasons. It checks the syntax, whether the domain takes mail, throwaway domains and shared addresses such as info@, suggests a correction for a likely typo, and with emails:read adds what the workspace knows about the address. deep=True also asks whether the mailbox exists, which is billed per address through pay as you go and needs emails:send, and tools.check_addresses checks up to 100 in one call.
  • A workspace on Business or Enterprise that sends at least 100,000 emails a month can buy a dedicated sending IP. For the workspace owner, billing.list_add_ons says whether it is for sale, what it costs, whether the workspace qualifies and whether it has one, billing.start_add_on_checkout returns the link where the person pays, and billing.cancel_add_on ends it at the end of the month already paid for. sending.list_dedicated_ips and sending.get_dedicated_ip read each IP with its status and warmupPercent, since a new IP is warmed up over several weeks.
  • domains.get_mail_app_settings returns smtpSubmission, the SMTP server on port 587 for apps, devices and libraries that only offer STARTTLS. Its security is starttls, a new member of MAIL_APP_SECURITIES, and it takes the same username and app password as smtp.
  • imports can read a live mailbox, as the Migrations page of the app does: discover_mailbox finds the mail server for an address, check_mailbox signs in once and lists the folders and how many messages an import would bring, and connect_mailbox starts copying the mailbox into one address, with contacts and calendars to bring those across too. The old mailbox is only ever read, a message the address already holds is skipped, and the password is kept sealed until the import finishes and for 30 days at most. An import waits by itself when the old provider slows it down, with the status parked, and when the password stops working it is needs-password and resume sends a new one.
  • Every import carries source, remote and children, and ImportFormat gains imap and microsoft.
  • calendar.import_ics and contacts.import_vcf take an iCalendar or vCard file as bytes and queue it. Events become events of your own and nobody on them is sent anything, cards become contact cards that join no audience, and what is already here is left as it is and counted, so sending a file twice adds nothing. list_imports, list_all_imports and iterate_imports read the imports of each kind, get_import reads one with its counts and a report of what it left out and why, and undo_import deletes everything an import added.
  • me.list_requests, me.list_activity and me.stats let a key read its own request log, its own history and its own figures with no scope at all, so a key that can only send can still watch itself. They read the calling key and nothing else: keys.list_requests, keys.list_workspace_requests and keys.stats are still the ones that reach other keys, behind keys:read. me.stats fills sends only when the key holds emails:read and leaves it None otherwise, and an OAuth access token is refused with 403 api_key_only, because calls made with one are not logged.
  • Every reader of the request log, in me and in keys, takes two more filters: statuses= keeps the calls answered with one of up to 20 exact HTTP status codes, and path= keeps the calls to one route, whatever the method. path= matches the route, not the exact path: an id counts as :id and an email address as :address, so /emails/:id reads the calls made to any single email, and a path that ends in * reads every route that starts with it. Both combine with failed_only=, since= and until=.
  • The new automations namespace holds emails and other steps that run by themselves for each contact: a welcome series when somebody joins an audience, a nudge after a trial starts, a note on a birthday. You edit a draft definition and publish it, which saves a numbered version and sets the automation live, and each contact stays on the version they entered on. list, list_all, iterate, get, create, update and delete manage them, list_starters returns ready-made definitions, pause, resume, archive and duplicate change their state, send_test sends the email of one step to one address, list_versions and restore_version read the published versions and copy one back into the draft, and stats returns totals, per-step numbers and a daily series.
  • list_enrollments, list_all_enrollments, iterate_enrollments and get_enrollment read who is in an automation and what each step did for them, enroll puts a contact in and exit_enrollment takes one out. Reading needs automations:read and every change automations:write, and publish, resume and send_test also need emails:send. A draft that cannot run is refused with 422 invalid_automation, and problems on the error lists every problem that blocks it.
  • The new events namespace records what your contacts did, from your own code: send stores one event against a contact, starts every live automation whose trigger names it and ends the waits that were holding out for it, send_batch records up to 100 in one call and reports per event, and list_names returns the event names the workspace has seen. Both sends carry an Idempotency-Key, generated per call or passed as idempotency_key=, so a retry never records an event twice, and a key or an app may send 600 events a minute. contacts.list_events, list_all_events and iterate_events read the events of one contact.
  • WEBHOOK_EVENTS gained automation.entered, automation.exited, automation.paused and automation.webhook. Like form.*, they belong to the whole workspace, have to be named in eventTypes, and never reach an endpoint limited to some addresses or domains.
  • A sign-up form field can fill more of the contact: mapsTo also takes phone, company, jobTitle, website and birthday, saved on the contact card when the sign-up is accepted and only where the card has nothing yet. A single contact now comes with signUps, its last 20 sign-ups with their answers, for a caller that holds forms:read.

0.0.2

The second release adds the 55 methods the TypeScript SDK gained since 0.0.1, so it covers all 485 again.

  • contacts.list_cards, list_all_cards, iterate_cards, get_card, create_card, update_card and delete_card read and write the address book as contact cards, with phone numbers, postal addresses, websites, organisation, job title, birthday and the name in parts. Phones and computers that sync the address book over CardDAV get every change on their next sync.
  • calendar.list_feeds, create_feed, reset_feed and delete_feed manage secret links that publish the calendar to Google Calendar, Outlook or Apple Calendar, and list_subscriptions, create_subscription, update_subscription, refresh_subscription and delete_subscription manage the calendars you subscribe to by link. respond_to_event can propose a new time, and decline_proposal keeps the original one.
  • Every event carries subscriptionId, rdates and recurrenceId, for the subscription it comes from, the occurrences added outside its rule and the start a changed occurrence replaces.
  • domains.get_mail_app_settings, list_app_passwords, create_app_password, update_app_password, delete_app_password and send_mail_app_setup put an address into Apple Mail, Gmail, Outlook, Thunderbird or any other mail app over IMAP, SMTP and POP3, and its calendar and contacts over CalDAV and CardDAV. update_mail_app_settings turns each kind of connection on or off.
  • domains.update takes senderName, the name mail from a domain goes out under when the sending address has no name of its own.
  • knowledge is new: the notes, files and web pages the AI uses when it writes replies, drafts email and answers in the assistant. It lists, searches, adds, refreshes and removes items, suggests notes, flags duplicates and conflicts, and keeps sites, sitemaps, feeds and Zendesk help centers in step through connectors.
  • threads.reply_suggestions reads the replies the reading pane suggests under the latest message of a thread. settings.update takes replySuggestions, semanticSearch and knowledgeLearning to turn those features off for the workspace.
  • threads.list, list_all and iterate take semantic to match the words of a query by meaning, and address to keep the threads delivered to one address. tracking.list, list_all, iterate and get_stats take address too.
  • emails.compose takes draft, withSubject, from, bcc, send, timeZone, template, templates and files, so one description can write or change a whole email.
  • tools.read_verification_code finds the sign-in or verification code in a message, and tools.estimate_cost prices every plan for a usage. Neither needs a scope.
  • settings.get and settings.update reach every setting the app has: @domain sets a whole domain, and None lets a scope inherit again. drafts.create takes forwardOf to forward a message, and templates.publish takes expected_version.
  • provider_imports moves an account across from SendGrid, Postmark, Mailgun and Mailchimp as well as Resend, and threads.counts counts drafts and labels too.
  • IMPORT_FORMATS and ImportFormat include proton, the format a mailbox import reports for a Proton Mail export.
  • The messages threads.get returns carry sentWith, forwardedFrom and verificationCode, and senders.get and senders.research share what is known about a domain with every workspace.
  • drafts.update keeps the attachments and the forward of a draft, settings.update with workspaceName renames the workspace, and the security.verify_step_up docs list all 40 calls that ask for a verification code.

0.0.1

The first release. It covers the whole TypeScript SDK as it stood when this release was cut: 430 methods in 41 namespaces, each under its TypeScript name in snake_case. A parity check proves that every one of them sends exactly the request its TypeScript twin sends, once with no options and once with every option set.

  • Nextmail and AsyncNextmail have an attribute for every namespace, from emails, threads and templates to provider_imports, dns_connections and account. listAll is list_all, getActive is get_active, and tempMail is temp_mail.
  • A request body is a dict whose keys keep the API’s camelCase names, the options of a call are snake_case keyword arguments such as idempotency_key= and limit=, and a response comes back as a dict. Every body and result has a TypedDict in nextmail.types, named as in TypeScript.
  • AsyncNextmail has the same methods with the same arguments, awaited, and runs on asyncio and on trio.
  • Every paginated resource has list for one page, list_all for every item as a list, and iterate, which yields items and fetches the next page only when it gets there.
  • An API refusal raises NextmailApiError, with status, type, code, param and request_id, and is_validation, is_not_found, is_rate_limited, is_step_up_required, is_retryable and the other checks. No response at all raises NextmailNetworkError, with is_timeout when the deadline passed.
  • from nextmail import nextmail is a ready-made client built from NEXTMAIL_API_KEY the first time it is touched, and init configures it once at startup. create_temp_mail and create_async_temp_mail open disposable inboxes with no credential.
  • access_token= takes an OAuth access token or a function that returns one, called before every request. verify_webhook_signature checks a delivery in constant time and returns the parsed event. client.raw.request reaches an endpoint no method wraps yet.
  • Reads are retried on 408 and 5xx, and a 429 only when it carries Retry-After. timeout bounds the whole attempt, the response body included, and a credential is never sent over plain HTTP except to a server on this machine.
  • It needs Python 3.10 or newer, and depends only on httpx, anyio and typing-extensions.