---
title: "Files, imports and settings"
description: "Every command for the files the mailbox holds, importing an old mailbox or an account at another provider, the calendar found in mail, and the settings of the workspace and of each address."
url: "https://nextmail.sh/docs/cli/files"
area: "CLI"
category: "Commands by area"
---

# Files, imports and settings

Every command for the files the mailbox holds, importing an old mailbox or an account at another provider, the calendar found in mail, and the settings of the workspace and of each address.

## Overview

Five namespaces cover what sits around the mail itself. `nextmail files` is the Files page: every attachment sent and received and every file uploaded, with its bytes and the download links it went out as. `nextmail imports` brings an old mailbox into one address, and `nextmail provider-imports` brings an account across from Resend, SendGrid, Postmark, Mailgun or Mailchimp. `nextmail calendar` reads the events found in mail, and `nextmail settings` reads and changes the mailbox preferences and the signature and tracking of each address.

- An id says what it names: `file_` for a file, `imp_` for a mailbox import, `pimp_` for an import from another provider and `cal_` for a calendar event, each followed by 24 hex characters. A download link has an id of its own, from `files list-links` or `files create-link`.
- `--address-id` on an import is the id of an address, from `nextmail domains list-addresses <id>`, not the address itself.
- The namespaces also answer to `file`, `import`, `provider-import` or `providerImports`, and `setting`. Verbs take the usual aliases where they have them: `ls` for `list`, `show` and `view` for `get`, `new` and `add` for `create`, `edit` for `settings update`, and `rm`, `del` and `remove` for `files delete`.
- None of these commands asks a browser sign-in for a verification code. The ones that change something for good ask you to confirm, and `--yes` answers for a script.
- `nextmail <command> --help` lists every argument and flag with its type, the scope the call needs, its method and path, and what comes back. Add `--json` for the same page as data.

## Files

`nextmail files` reads and manages every file the mailbox holds: attachments that came in, attachments that went out, and files uploaded to the Files page. `nextmail open files` opens the same page in the web app.

| Command | What it does |
| --- | --- |
| nextmail files list | List one page of files with name, type, size, direction, the address each came to and whether it can be deleted |
| nextmail files get <id> | Read one file, with the thread and message it belongs to, its `usage` and `deletable` |
| nextmail files stats | Count the files and the bytes they take, split into received, sent and uploaded, with the top types and addresses, the last 30 days and the links still working |
| nextmail files download <id> | Fetch the bytes of a file exactly as stored, into `--out <file>` or to stdout when piped |
| nextmail files list-links <id> | List the download links a file went out as, newest first, with how often each was fetched and whether it was revoked |
| nextmail files create-link <id> | Publish the file at a new public download link that opens without signing in |
| nextmail files revoke-link <id> <link-id> | Stop a public link for good, in mail already sent too. Asks you to confirm |
| nextmail files upload <data> | Upload a file from a path, or from stdin with `-`, up to 100 MB |
| nextmail files delete <id> | Delete an upload that nothing depends on, for good. Asks you to confirm |
| nextmail files delete-many <ids...> | Delete up to 100 files in one call and report the ones kept and the ones not found. Asks you to confirm |
| nextmail files revoke-all-links <id> | Make a file private: every public link to it stops working, in mail already sent too, and `revoked` says how many did. Asks you to confirm |

- `files list` narrows with `--q` (the name and the type), `--kind` (`image`, `pdf`, `audio`, `video` or `text`), `--direction` (`inbound`, `outbound` or `uploaded`), `--address`, `--since` and `--until`, and sorts with `--sort` (`newest`, `oldest`, `largest` or `name`). `--since` and `--until` take an ISO 8601 date or date-time: `--since` includes its moment and `--until` stops before it.
- Only an upload that nothing depends on can be deleted, and `deletable` says so ahead of time. `usage` says what keeps any other file: `received`, `sent`, `linked` for an upload whose download link still works, or `scheduled` for one attached to a message that has not gone out. `delete` refuses those with 409 `file_in_use`. `delete-many` deletes what it can, lists the rest in `kept` with a reason each, and lists unknown ids in `missing`.
- `upload` reads the file at the path you give and stores it under that file’s name, with the type its extension implies. `--filename` and `--content-type` override them. From stdin, `-` needs `--filename`, and without `--content-type` the type is `application/octet-stream`. The upload waits up to 10 minutes, which `--timeout-ms` changes.
- The id `upload` returns attaches the file to a send as `{ "fileId": "…" }` in `nextmail emails send --attachments`, which is how a file over the 10 MB inline limit goes out.
- An empty file is 400 `upload_empty`, a program or script (judged by its name) is 400 `upload_dangerous`, and a file over 100 MB is 413 `upload_too_large`. A workspace keeps as many uploads as its plan allows, from 10 GB on Free to 1 TB on Enterprise, and takes 500 uploads an hour.
- `download` needs `--out <file>` on a terminal and stops with exit code `2` without it. Piped, the bytes go to stdout, and `--out -` asks for stdout too. The whole file is held in memory.
- `create-link` makes a new link on every call, with its own download count, and the link works until it is revoked or the file is deleted. It lives on the files domain of `--domain` when that domain has one, such as `files.acme.com`, else on the files domain of the file’s address, else on the API address. A program or script is refused with 422 `file_unshareable`.
- `revoke-link` is safe to repeat: a link already revoked comes back unchanged.
- A key or sign-in limited to particular addresses or domains sees only the files that arrived at them, never the files uploaded for the whole workspace, and its own uploads belong to the first address it holds.
- The files index starts on the day it shipped. Older attachments are still on their messages, where `nextmail threads list-attachments <id>` reads them.

## Mailbox imports

`nextmail imports` brings an old mailbox into one address: Google Takeout archives, `.mbox` files from Apple Mail, Thunderbird and most desktop apps, `.eml` files, and `.zip` or `.tgz` archives holding any of those, up to 100 GB a file and 50 files an import. Threads, dates and labels come across. Imported mail is quiet: it runs no rules, forwards, notifications, summaries or webhooks.

`import-files` is the one most people need: it creates the import, uploads every file in parts with a progress line, and starts it. The other verbs are those steps one at a time, for finishing an upload that stopped or for driving it yourself. `create` returns the plan, `chunkBytes` and each file’s `chunks`, `upload-chunk` sends one part, `upload-state` says which parts arrived, and `start` queues the import. `nextmail open imports` shows the same imports in the web app.

| Command | What it does |
| --- | --- |
| nextmail imports list | List one page of the imports in the workspace, newest first, with status, bytes read and counts. `--address-id` keeps one address |
| nextmail imports get <id> | Read one import with its status, progress and counts. Poll it until it reads `completed`, `failed` or `cancelled` |
| nextmail imports create --address-id <value> --files <json\|@file\|-> | Create an import from a list of `{ name, bytes }` and get its upload plan, with `status` `uploading` |
| nextmail imports upload-state <id> | For each file, the indexes of the parts already stored, so a stopped upload sends only what is missing |
| nextmail imports upload-chunk <id> <file> <chunk> <data> | Upload one part of one file, from a path or from stdin with `-`. Sending a part again replaces it |
| nextmail imports start <id> | Check that every part arrived, recognise each file’s format and queue the import |
| nextmail imports cancel <id> | Stop the import at its next checkpoint. Mail already imported stays. Asks you to confirm |
| nextmail imports list-failures <id> | List each message or archive entry that did not come across, with the reason |
| nextmail imports delete-upload <id> | Delete the uploaded files. Mail already imported stays. Asks you to confirm |
| nextmail imports import-files --address-id <value> --files <path> | Create, upload and start an import in one command, and return once it is queued |
| nextmail imports discover-mailbox <email> | Find the mail server behind an old address, and whether it takes an app password, a password or a Microsoft sign-in |
| nextmail imports check-mailbox --email <value> --password <value> | Sign in to the old mailbox once and list its folders with their message counts. Nothing is copied or kept |
| nextmail imports connect-mailbox --address-id <value> --email <value> --password <value> | Start copying the old mailbox into an address, straight from its mail server. `--contacts` and `--calendars` bring those too where the provider offers them |
| nextmail imports resume <id> | Carry a waiting import on. Add `--password` when its status is `needs-password` |

- The address has to be one on the workspace’s own domains that the key or sign-in may act for. Only one import runs per address: another while one is queued or running is 409 `already_running`.
- `import-files` takes `--files` once per file, or several paths separated by commas, and sends each under its own file name. `--options` takes JSON such as `{"keepInbox":false,"includeSpam":true}`. On `create` the same three are switches: `--options-keep-inbox`, `--options-include-spam` and `--options-include-trash`, each turned off with `--no-` in front, as in `--no-options-keep-inbox`.
- `keepInbox` is on by default, so mail from the old inbox lands in Inbox with its unread state. Off files everything under Archive. Spam and trash stay behind unless you include them.
- `create` takes `--files` as JSON, inline or from a file with `@path`, and each `bytes` must be the exact size of the file you then upload.
- Each part is exactly `chunkBytes` long, except the last part of a file, and a part of the wrong length is 400 `bad_chunk`. `start` refuses a file with parts missing with 412 `missing_chunks`, and one that is not an archive or a mailbox with 400 `unsupported_file`. On an import that already left `uploading`, it returns the import unchanged.
- If a part still fails after its retries, `import-files` stops with the import left in `uploading`. The block below sends the missing parts of the first file and starts it.
- An import reports `processedBytes` out of `totalBytes`, and `counts` with `seen`, `imported`, `duplicate`, `filtered`, `failed` and `threads`. `lastError` is set only when `status` is `failed`.
- `list-failures` gives each failure a `reason`: `too-large` (over 50 MB), `unparseable`, `no-date`, `storage-error`, `unreadable-entry`, `encrypted-entry` or `archive-limit`, with the subject and sender where they could be read.
- `cancel` on a finished import is 409 `not_cancellable`. `delete-upload` cancels an import that is still uploading, and refuses one that is queued or running with 409 `still_running`, so cancel that first.

**Finish an upload that stopped**

```
nextmail imports get "$import_id" --json > import.json
nextmail imports upload-state "$import_id" --json > state.json
chunk=$(jq .chunkBytes import.json)
chunks=$(jq '.files[0].chunks' import.json)
for i in $(seq 0 $((chunks - 1))); do
  jq -e --argjson i "$i" '.received[0] | any(. == $i)' state.json > /dev/null && continue
  dd if=takeout-001.zip bs="$chunk" skip="$i" count=1 2> /dev/null |
    nextmail imports upload-chunk "$import_id" 0 "$i" -
done
nextmail imports start "$import_id"
```

## Imports from another provider

`nextmail provider-imports` moves a workspace across from Resend, SendGrid, Postmark, Mailgun or Mailchimp with one API key, and `--provider` says which. Suppressions keep their reason, segments and lists become audiences, subscribed contacts arrive with their names, and templates arrive as HTML templates with their variables declared. Webhooks are registered switched off, because deliveries here are signed differently. A signing key or a token cannot leave the provider that made it, so domains and API keys come back as a checklist in the report instead.

| Command | What it does |
| --- | --- |
| nextmail provider-imports inspect <api-key> --provider <value> | Count what the account holds, per resource, before importing. Nothing is stored and the key is not kept |
| nextmail provider-imports create --provider <value> --provider-key <value> --resources <a,b> | Queue an import of the resources you name |
| nextmail provider-imports list | List one page of the imports from sending providers, newest first, each with its report |
| nextmail provider-imports get <id> | Read one import: its status, the step it is on and the report so far |
| nextmail provider-imports cancel <id> | Stop the import and erase the provider key. What already came across stays. Asks you to confirm |

- Pass the provider key as `@path` to read it from a file, or as `-` to read it from stdin, so it stays out of your shell history and the process list. A key typed on the command line still works, with a warning. `--dry-run` prints the body with the key redacted.
- `--resources` takes any of `suppressions`, `audiences`, `contacts`, `templates`, `webhooks`, `domains` and `api-keys`, comma separated or repeated.
- A key that can only send is 400 `restricted_key`. Create one with more access at the provider for the import, and revoke it afterwards.
- `inspect` reads the first page of each resource and returns `resources`, what the key can bring across, and `counts`, one `{ count, more }` per resource, with `more` set where a resource runs past its first page.
- One import runs per workspace at a time, and a second is 409 `already_running`. Running the same import twice duplicates nothing. The key is held encrypted only while the import runs, and is erased when it ends, fails or is cancelled.
- Contacts who unsubscribed at the provider are left out and counted in `report.contacts.unsubscribed`.
- `report.domains` lists each domain at the provider with a `state`: `absent` when it is not in this workspace, `added` when it is but is not verified, and `verified`, with the records it had there. Add a missing one with `nextmail domains create`. `report.apiKeys` names the keys to create again with `nextmail keys create`.
- With a browser sign-in only the workspace owner may use these commands, and a member gets 403 `owner_only`. An API key is not held to that. A key or sign-in limited to particular addresses or domains cannot inspect or create an import, since audiences, suppressions and templates belong to the whole workspace.
- `create` also needs the scope of each resource it brings in: `audiences:write` for audiences, `contacts:write` and `audiences:write` for contacts, `templates:write` for templates, `webhooks:write` for webhooks and `domains:read` for domains.
- `--provider` takes `resend`, `sendgrid`, `postmark`, `mailgun` or `mailchimp`, and defaults to `resend`. Resend needs a full-access key, SendGrid a key with read access, Postmark a Server API token, Mailgun a private API key from either region, and Mailchimp an API key ending in its datacenter, such as `-us6`.
- What a provider has no such thing for, or the key cannot read, is left out of `resources` and of the import. Postmark keeps domains and sender signatures behind an Account token, which the import does not take, and Mailchimp has no webhooks for sending events and does not list its API keys.
- SendGrid hands out contacts through an export it prepares first, so the contacts step waits for it. Mailchimp shares only the editable sections of a template, which arrive as a draft.

## Calendar

`nextmail calendar` reads and changes the calendar. `list-events` expands every event into its occurrences inside a window you give, so a weekly meeting is one row per week, and `get-event` and `get-event-ics` read one event whole. Five more change events as the Calendar page does, the feed commands manage the links that publish the calendar, the subscription commands manage the other calendars you subscribe to, and `nextmail threads get-event` reads the event a thread carries. `nextmail open calendar` opens the calendar in the web app.

| Command | What it does |
| --- | --- |
| nextmail calendar list-events --from <when> --to <when> | List one page of occurrences between two moments, sorted by start time, each pointing back to its event through `eventId` |
| nextmail calendar get-event <id> | Read an event with its attendees and their answers, its recurrence rule, excluded dates, organiser and reminders |
| nextmail calendar get-event-ics <id> | Download the event as an iCalendar document, printed or written to `--out <file>` |
| nextmail calendar create-event --summary <value> --start <when> --end <when> | Put an event on the calendar. `--attendees` invites people from the address in `--from` |
| nextmail calendar update-event <id> | Change an event you organise and send the update to everyone invited |
| nextmail calendar cancel-event <id> | Call off a meeting you organise and tell everyone invited, once you confirm |
| nextmail calendar delete-event <id> | Take an event off the calendar without telling anybody, once you confirm |
| nextmail calendar respond-to-event <id> --response <value> | Answer an invitation with `ACCEPTED`, `DECLINED` or `TENTATIVE`, and tell the organiser |
| nextmail threads get-event <id> | Read the event a thread carries, to answer it |
| nextmail calendar decline-proposal <id> --attendee <email> | Keep the original time of a meeting you organise after a guest proposed another one, and tell the guest |
| nextmail calendar list-feeds | List the secret links that publish your calendar to Google Calendar, Outlook or Apple Calendar |
| nextmail calendar create-feed --name <value> --mode <full\|busy> | Make a calendar link with every detail or busy times only, and print its address |
| nextmail calendar reset-feed <id> | Give a calendar link a new address so the old one stops working, once you confirm |
| nextmail calendar delete-feed <id> | Turn a calendar link off for good |
| nextmail calendar list-subscriptions | List the other calendars you subscribe to by link, with their status |
| nextmail calendar create-subscription --url <link> | Subscribe to a calendar by its iCalendar link. `--name` and `--color` are optional |
| nextmail calendar update-subscription <id> | Rename a subscription with `--name` or recolour it with `--color` |
| nextmail calendar refresh-subscription <id> | Read a subscribed calendar again now |
| nextmail calendar delete-subscription <id> | Unsubscribe and take its events off your calendar |
| nextmail calendar import-ics <data> | Import an .ics file, read from a path or from stdin with `-`. Its events become your own and nobody on them is emailed |
| nextmail calendar list-imports | List one page of the calendar imports, newest first, with what each added and left out |
| nextmail calendar get-import <id> | Read one calendar import with its report |
| nextmail calendar undo-import <id> | Remove every event one import added. Asks you to confirm |

- `--from` and `--to` are ISO 8601 date-times such as `2026-10-01T00:00:00Z`. `--to` must be after `--from` and at most 366 days later, since a repeating series has no end to list up to. A missing bound is 422 `invalid_parameter`. A bound that does not parse, a reversed or overlong window, or an unknown zone is 400 `invalid_parameter`.
- `--timezone` is an IANA zone such as `Europe/London`, UTC when left out. It expands the events stored without a zone of their own, which decides the day an all-day event lands on.
- `get-event` and `get-event-ics` take the `eventId` of an occurrence, not the iCalendar `uid`. A recurring series is one event, so its `start` and `end` describe the first instance.
- Cancelled events are listed too, with `status` `CANCELLED`. `myPartstat` is the answer recorded for any address the workspace holds on its own domains, and null when none of them is an attendee.
- Paging carries on with `--cursor` and the same window. A key or sign-in limited to particular addresses sees only the events one of them organises or attends, and any other event is a 404.
- `get-event-ics` declares `METHOD:PUBLISH`, so importing it shows the event as it stands rather than offering to accept or decline. Timed events are written in the zone they were made in, with the rules of that zone attached, and all-day events as dates. A repeating series comes with its changed and cancelled instances. `DTSTAMP` is the time of the download, so two downloads of an unchanged event differ on that line.
- Changing needs `calendar:write`. Inviting, updating or cancelling a meeting with attendees, and every answer, goes out by email, so it needs `emails:send` too, and `--from` has to be an address the key may send as. `--no-send-invites` keeps a change to your own calendar.
- The feed and subscription commands need `calendar:read` to list and `calendar:write` to change, and a key limited to particular addresses or domains cannot use them, because they cover the whole calendar. `decline-proposal` emails the guest, so it needs `emails:send` too.

## Settings

`nextmail settings` reads and changes the mailbox preferences, such as timezone, time format and the blocklists. An address can have its own `signature`, `openEmailSignature` (the Nextmail footer), `trackOpens` and `trackClicks`, and an address or a whole domain its own `externalImages`, `trustedSenders` and blocklist. Name the address with `--address`, `*@acme.com` for the catch-all of a domain, or `@acme.com` for the whole domain.

| Command | What it does |
| --- | --- |
| nextmail settings get | Read every setting with defaults filled in. With `--address`, the settings read the way they apply to that address, catch-all or domain |
| nextmail settings update | Change the settings you pass and keep the rest. The answer is every setting, read back after the write |

- Without `--address`, `get` reads the four per-address settings as the built-in defaults: no signature, the Nextmail footer on, and open and link tracking off. With it they come from the address’s own values, then from its domain’s catch-all when the catch-all caught that address, then from the defaults. A plus address with no settings of its own reads its base address’s.
- Without `--address`, `update` refuses `--signature`, `--nextmail-signature`, `--track-opens` and `--track-clicks` with 422 `address_required` and writes nothing. With an address or a catch-all it takes those four, `--external-images`, `--trusted-senders` and the blocklist, with `@domain` the last three only, and anything else is 422 `not_per_address`. The address has to be in this workspace, a catch-all needs a verified domain here with its catch-all on, and `@domain` a domain in this workspace.
- Every switch turns off with `--no-` in front, such as `--no-track-opens` or `--no-external-images`.
- `--signature` is HTML of at most 150,000 characters, sanitised on write, so what comes back is what will be sent. An empty string removes it. Whether a send adds it is up to the send: see `--signature` in `nextmail emails send --help`.
- Every setting has its own flag, such as `--time-format`, `--week-start` or `--undo-send-enabled`, and `--data` takes them as JSON instead, inline, from a file with `@path` or from stdin with `-`. Without `--address`, keys the settings do not know are dropped without an error. A known key with the wrong type is 422 `invalid_parameter`.
- A list such as `blockedDomains` is replaced whole, so read it first and send it back with your change, as the example below does. A blocklist entry too short to be a rule is 422 `blocklist_entry_too_broad`.
- `--timezone` is saved as given, without checking, so check a zone before you send it.
- Without `--address`, the privacy fields (`externalImages`, `trustedSenders`, `blockedSenders`, `blockedDomains`, `blockedWords`, `useDefaultBlockedWords`, `semanticSearch`, `replySuggestions` and `knowledgeLearning`) and `--workspace-name` belong to the workspace, and a key or sign-in limited to particular addresses or domains cannot change them. With `--address` it may name only an address it holds, or a catch-all or a domain it holds whole. Either refusal is 422 `capability_unsupported`.
- An update with nothing in it changes nothing and returns the current settings. `defaultEmailAlias` only preselects the From address in the web app composer, and the API never uses it to choose a sender.
- `null` in `--data` removes a value the scope sets itself, so `--address sales@acme.com --data '{"externalImages":null}'` makes the address inherit `externalImages` again. `get` lists what a scope sets itself under `overrides`.
- Three switches belong to your account, not to the workspace. `--inbox-tabs` shows the inbox as Primary, Promotions, Updates, Social and Forums, `--primary-only-alerts` keeps notifications to Primary mail while the tabs are on, and `--phone-follow-ups` sends a push when a reminder comes due with no reply.

`nextmail out-of-office` reads and sets the automatic reply an address sends while its owner is away, the Out of office tab of an address in the app. It is saved for one address, or for the catch-all of a domain written `*@acme.com`.

| Command | What it does |
| --- | --- |
| nextmail out-of-office list | List every out of office reply saved in the workspace. `--address` reads the reply of one address, which shows `enabled: false` when none was saved |
| nextmail out-of-office set <address> --message <value> | Save the reply of an address, replacing whatever was saved. `--starts-at`, `--ends-at`, `--subject`, `--contacts-only` and `--no-enabled` are optional |
| nextmail out-of-office clear <address> | Remove the saved reply, so nothing is answered from the address any more. Asks you to confirm |

- `--message` is plain text of 1 to 10,000 characters. Without `--starts-at` a new reply starts now and a reply that is already on keeps its start, and without `--ends-at` it stays on until it is switched off. Changing the start begins a new away period in which everyone is answered once more. `--no-enabled` saves the text and keeps the reply paused.
- Each sender is answered once for the whole away period. Spam, newsletters and other bulk mail, automatic mail, bounces, blocked senders and the workspace’s own addresses get no reply, and `--contacts-only` answers only contacts and people the workspace has written to.
- `active` in the answer says whether mail arriving now is answered. A sign-in or key limited to particular addresses or domains reaches only the addresses it holds, and a catch-all only when it holds the domain whole.

## Examples

**Upload a file and share it by link**

```
file_id=$(nextmail files upload ./price-list.pdf --json | jq -r .id)
nextmail files create-link "$file_id" --domain acme.com --json | jq -r .url
nextmail files list-links "$file_id"
nextmail files download "$file_id" --out copy.pdf
```

Each `create-link` makes a new link, so run it once and read the link back with `list-links`. `revoke-link` stops it later, in mail that already went out as well.

**Clear out every upload that nothing uses**

```
nextmail files list --direction uploaded --all | jq -r 'select(.deletable) | .id' > deletable.txt
wc -l < deletable.txt
xargs -r -n 100 nextmail files delete-many --yes --json < deletable.txt | jq -c '.kept[]'
```

With `--all` in a pipe, `files list` prints one file per line. `xargs -n 100` hands `delete-many` at most 100 ids a call, and any file that became used in between comes back in `kept` with its reason rather than failing the call.

**Import an old mailbox and follow it**

```
domain_id=$(nextmail domains list --all | jq -r 'select(.domain == "acme.com") | .id')
address_id=$(nextmail domains list-addresses "$domain_id" --all | jq -r 'select(.address == "ada@acme.com") | .id')
nextmail imports import-files --address-id "$address_id" --files ~/Downloads/takeout-001.zip --files ~/Downloads/takeout-002.zip --json > import.json
import_id=$(jq -r .id import.json)
until nextmail imports get "$import_id" --json | jq -e '.status != "queued" and .status != "running"' > /dev/null; do
  sleep 60
done
nextmail imports get "$import_id" --json | jq '{status, counts, lastError}'
nextmail imports list-failures "$import_id" --json | jq -r '.data[] | [.reason, .subject] | @tsv'
```

`--dry-run` on `import-files` prints the `POST /imports` it would send, with each file’s name and size, and uploads nothing. `list-failures` reads 100 at a time: pass the `nextCursor` it printed as `--after` for the next page.

**Move from Resend**

```
nextmail provider-imports inspect @resend-key.txt
nextmail provider-imports create --provider-key @resend-key.txt --resources suppressions,audiences,contacts,templates,webhooks,domains,api-keys --json > resend.json
pimp_id=$(jq -r .id resend.json)
until nextmail provider-imports get "$pimp_id" --json | jq -e '.status != "queued" and .status != "running"' > /dev/null; do
  sleep 10
done
nextmail provider-imports get "$pimp_id" --json | jq '.report | {contacts, domains: [.domains[] | {name, state}], apiKeys: [.apiKeys[].name]}'
```

**Read a month of meetings**

```
nextmail calendar list-events --from 2026-10-01T00:00:00Z --to 2026-11-01T00:00:00Z --timezone Europe/London --all |
  jq -r 'select(.status != "CANCELLED") | [.start, .summary, .myPartstat] | @tsv'
nextmail calendar get-event cal_8d3f0a2b9c4e41f7a6b5c2d1 --json | jq '.attendees[] | {email, partstat}'
nextmail calendar get-event-ics cal_8d3f0a2b9c4e41f7a6b5c2d1 --out standup.ics
```

**Signature, tracking and the blocklist**

```
nextmail settings get --address sales@acme.com --json | jq '{signature, openEmailSignature, trackOpens, trackClicks}'
nextmail settings update --address sales@acme.com --signature "$(cat signature.html)" --no-track-clicks --dry-run
nextmail settings update --address sales@acme.com --signature "$(cat signature.html)" --no-track-clicks
nextmail settings update --address '*@acme.com' --no-track-opens
nextmail settings update --address @acme.com --no-external-images
nextmail settings update --timezone Europe/London
nextmail settings get --json | jq -c '{blockedDomains: ((.blockedDomains + ["spam.example"]) | unique)}' |
  nextmail settings update --data -
```

The dry run prints the `PATCH /settings?address=sales%40acme.com` and its body without sending it. The catch-all line sets tracking for every address the catch-all of `acme.com` picks up, and the last line adds one domain to the blocklist without dropping the others.

## Scopes, confirmations and errors

| Scope | Commands |
| --- | --- |
| files:read | `files list`, `get`, `stats`, `download`, `list-links` |
| files:write | `files create-link`, `revoke-link`, `upload`, `delete`, `delete-many` |
| threads:read | `imports list`, `get`, `list-failures` |
| threads:write | `imports create`, `upload-state`, `upload-chunk`, `start`, `cancel`, `delete-upload`, `import-files` |
| settings:read | `provider-imports list`, `get`, `settings get` and `out-of-office list` |
| settings:write | `provider-imports inspect`, `create`, `cancel`, `settings update`, and `out-of-office set` and `clear` |
| calendar:read | `calendar list-events`, `get-event`, `get-event-ics`, `list-feeds`, `list-subscriptions`, `threads get-event` |
| calendar:write | `calendar create-event`, `update-event`, `cancel-event`, `delete-event`, `respond-to-event`, `decline-proposal`, `create-feed`, `reset-feed`, `delete-feed`, `create-subscription`, `update-subscription`, `refresh-subscription`, `delete-subscription` |

- A sign-in or key without the scope stops with exit code `4`, names the missing scope and says how to get it.
- `files revoke-link`, `files delete`, `files delete-many`, `imports cancel`, `imports delete-upload` and `provider-imports cancel` ask you to confirm. Answering no exits with code `10` and changes nothing. Unattended and without `--yes`, they stop with exit code `2` before anything is sent.
- No command here asks for a verification code, with a browser sign-in or an API key, so `--yes` is all a script needs.
- `--dry-run` prints the request a change would send, with its body, and exits with code `0` without sending it or asking you to confirm. A file body is shown as its size and type.
- `files list`, `files list-links`, `imports list`, `provider-imports list` and `calendar list-events` read one page: `--limit` takes 1 to 100 and the server sends 25 when it is left out, and `--cursor` takes the `nextCursor` of the page before. `--all` reads every page, `--max <n>` stops after that many items, and `--ndjson`, or `--all` in a pipe, prints one JSON object per line. With `--json` they print one `{ items, hasMore, nextCursor }` document.
- `imports list-failures` pages its own way: `--after` takes the `nextCursor` of the page before, `--limit` is at most 100, the default, and there is no `--all`. With `--json` it prints `{ object, data, nextCursor }`.
- Reads and the changes that land the same way twice are retried after a network failure: `files revoke-link`, `imports upload-chunk`, `imports start` and `settings update`. Every other change is sent once. After a lost answer, look before trying again: a second `upload` stores a second copy and a second `create-link` makes a second link, a 404 on your second `files delete` means the first one worked, and a second `delete-many` lists what the first deleted in `missing`.
- A refusal exits with the code of its status: `4` for a 403, `5` for a 404, `6` for a 409, `7` for a 400 or a 422, and `8` for a 429.

## Where to go next

- [Files in the SDK](https://nextmail.sh/docs/sdk/files.md): The same calls from TypeScript, with every field of the answer.
- [Files in the API](https://nextmail.sh/docs/api/files/list.md): The REST endpoints the files commands call.
- [Every SDK method](https://nextmail.sh/docs/sdk/reference/methods.md): The imports, calendar and settings calls, each with its endpoint and scope.
- [Scripting](https://nextmail.sh/docs/cli/scripting.md): JSON output, exit codes and running unattended.
