Protocols and limits
Every SMTP, IMAP, POP3, JMAP, ManageSieve and HTTPS extension Nixt Server offers, and every built-in ceiling, timeout and connection limit.
SMTP
Extensions
| Extension | Port 25 (mx) | Ports 587 and 465 (submission) |
|---|---|---|
PIPELINING | Yes | Yes |
SIZE | Yes | Yes |
8BITMIME | Yes | Yes |
SMTPUTF8 | Yes | Yes |
ENHANCEDSTATUSCODES | Yes | Yes |
DSN | Yes | Yes |
CHUNKING and BINARYMIME | Yes | Yes |
LIMITS RCPTMAX=… MAILMAX=… | Yes | Yes |
STARTTLS | Before TLS | Port 587, before TLS |
REQUIRETLS | After TLS | After TLS |
AUTH PLAIN LOGIN SCRAM-SHA-256 OAUTHBEARER XOAUTH2 | Never | After TLS, until signed in |
BURL imap | Never | Yes |
FUTURERELEASE 2592000 <date> | Never | Yes: HOLDFOR and HOLDUNTIL on MAIL, up to 30 days; see Sending later |
HELP | Yes | Yes |
Commands: EHLO, HELO, STARTTLS, AUTH, MAIL, RCPT, DATA, BDAT, BURL, RSET, NOOP, VRFY (always 252), HELP, QUIT. EXPN, ETRN and ATRN answer 502.
Ceilings
| Ceiling | Value | Changeable |
|---|---|---|
| Message size | 25 MiB (26,214,400 bytes) | Lower only: [limits] message_size, limits.message_size |
| Recipients per message | 100 | Lower only: [limits] recipients, limits.recipients |
| Messages per connection | 100 | No |
| Command line | 4,096 bytes | No |
| Line of message data | 8,192 bytes | No |
| Reply line sent | 512 bytes | No |
One BDAT chunk | 1 MiB | No |
| Commands per session | 1,000 | No |
| Bad commands before closing | 10 | No |
Failed AUTH before closing | 3 | No |
| Header fields per message | 1,000 | No |
| Header section | 64 KiB | No |
| One header field | 8 KiB | No |
| MIME nesting depth | 32 | No |
| MIME parts per message | 1,000 | No |
| Addresses in one header | 1,000 | No |
| Local part of an address | 64 bytes | No |
| Domain | 255 bytes | No |
| Whole address path | 512 bytes | No |
Connections
| Port 25 | Submission | |
|---|---|---|
| Connections at once | 1,000 | 1,000 |
| From one address | 20 | 50 |
| From one network | 200 | 200 |
| Pause before the greeting | 2 seconds | None |
| Idle time between commands | 5 minutes | 10 minutes |
| Whole session | 1 hour | 1 hour |
A network is an IPv4 /24 or an IPv6 /48. Every mail listener’s ceilings can be changed, and rates added, in its [listeners.<name>] table.
IMAP
The server speaks IMAP4rev2 (RFC 9051) and IMAP4rev1, and advertises both. Its capabilities:
| Capability | What it lets an app do |
|---|---|
STARTTLS, LOGINDISABLED | Before TLS on port 143 only. |
AUTH=SCRAM-SHA-256, AUTH=PLAIN, AUTH=LOGIN, AUTH=OAUTHBEARER, AUTH=XOAUTH2 | Sign in. Only SCRAM-SHA-256 is offered before TLS. |
SASL-IR | Send the first sign-in step with AUTHENTICATE. |
ENABLE | Turn on extensions such as CONDSTORE, QRESYNC and UTF8=ACCEPT. |
IDLE | Be told of changes as they happen. |
NOTIFY | Be told of changes in other folders as well as the open one, without opening each. |
LITERAL+ | Send literals without waiting. |
UIDONLY | Once enabled, work with UIDs only (RFC 9586): message numbers are refused with UIDREQUIRED, fetches answer as UIDFETCH and removals as VANISHED, which saves memory in large mailboxes. |
UIDBATCHES | The UID ranges that divide the open mailbox into batches of a chosen size, newest first (RFC 10022), at least 500 messages a batch and at most 100,000 messages in one request for a range of batches. |
PARTIAL | A page of a search or a UID FETCH by position, counted from the oldest (1:50) or the newest (-1:-50) (RFC 9394). |
BINARY | Fetch and append parts without transfer encoding. |
MOVE | Move messages in one command. |
UIDPLUS | Learn the UIDs of appended, copied and moved messages. |
UNSELECT | Close a mailbox without expunging. |
NAMESPACE | Discover the folder namespaces: your own, and Other Users/ for mail you are a delegate for. |
ID | Exchange client and server identification. |
QUOTA | Ask about storage limits: the mailbox’s size and number of messages against its ceilings (STORAGE and MESSAGE). |
UTF8=ACCEPT | Use UTF-8 in folder names and messages. |
SORT, SORT=DISPLAY | Sort on the server, including by display name. |
THREAD=REFERENCES, THREAD=ORDEREDSUBJECT | Thread on the server. |
ESEARCH, ESORT, CONTEXT=SEARCH, CONTEXT=SORT | Compact search results, partial results and updating searches. |
SEARCHRES | Save a search result and use it as $. |
MULTIAPPEND | Append several messages at once. |
CATENATE | Build a message from parts already on the server. |
REPLACE | Replace a message, such as a draft, in one step. |
STATUS=SIZE | Ask a folder’s size. |
CONDSTORE, QRESYNC | Resynchronise quickly: only what changed, and what vanished. |
SPECIAL-USE | Find Drafts, Sent, Junk, Trash and Archive by use, and Scheduled and Snoozed (\Scheduled and \Snoozed, RFC 9979) once they are made. |
LIST-EXTENDED, LIST-STATUS | Richer folder listings, with counts in one command. |
OBJECTID | Stable ids for folders, messages and threads, the same as JMAP’s. |
PREVIEW | A message’s first words. |
SAVEDATE | When a message arrived in its current folder. |
ACL, RIGHTS=texk | Ask what you may do in a folder, and see who else may read your mail. |
URLAUTH, URLAUTH=BINARY | Make signed URLs to messages, for BURL. |
UNAUTHENTICATE | Sign out without disconnecting. Offered after signing in. |
METADATA | Folder and server annotations. |
COMPRESS=DEFLATE | Compress the connection. |
| Limit | Value |
|---|---|
| Connections at once | 2,000 |
| From one address | 30 |
| From one network | 200 |
| Idle time | 31 minutes |
| One command, including an appended message | 32 MiB |
| Commands per connection | 100,000 |
| Failed sign-ins before closing | 3 |
| Unparseable commands before closing | 10 |
POP3
| Capability | Meaning |
|---|---|
STLS | Before TLS on port 110. |
UIDL | Stable message identifiers. |
TOP | Fetch headers and the first lines. |
PIPELINING | Send commands together. |
RESP-CODES | Machine-readable response codes. |
EXPIRE NEVER | The server never deletes mail on its own. |
UTF8 USER | UTF-8 user names and passwords. |
LANG | Language negotiation for response texts. |
IMPLEMENTATION Nixt Server <version> | The server’s name and version. |
USER | After TLS. |
SASL <mechanisms> | Mechanisms that send no password before TLS, all of them after. |
POP3 serves the Inbox only.
| Limit | Value |
|---|---|
| Connections at once | 500 |
| From one address | 20 |
| From one network | 200 |
| Idle time | 15 minutes |
| Whole session | 1 hour |
ManageSieve
Port 4190 with STARTTLS: 500 connections at once, 20 from one address and 200 from one network. Capabilities: IMPLEMENTATION, VERSION 1.0, SIEVE with every supported extension, SASL after TLS, STARTTLS before it, NOTIFY mailto, MAXREDIRECTS 4, UNAUTHENTICATE. Limits are on Sieve filters and vacation replies.
JMAP
Capabilities
| Capability | Server-level values |
|---|---|
urn:ietf:params:jmap:core | maxSizeUpload 26,214,400 (as large as a message); maxConcurrentUpload 4; maxSizeRequest 10,485,760; maxConcurrentRequests 8, each per person, and a request past them is answered with the limit error; maxCallsInRequest 64; maxObjectsInGet 500; maxObjectsInSet 500; collationAlgorithms i;octet and i;ascii-casemap |
urn:ietf:params:jmap:mail | Per account: maxMailboxesPerEmail null, maxMailboxDepth null, maxSizeMailboxName 200, maxSizeAttachmentsPerEmail 50,000,000, emailQuerySortOptions receivedAt, size, from, to, subject, sentAt, hasKeyword, allInThreadHaveKeyword and someInThreadHaveKeyword, mayCreateTopLevelMailbox true |
urn:ietf:params:jmap:submission | Sending. Per account: maxDelayedSend 2,592,000 (30 days), and submissionExtensions with FUTURERELEASE, so HOLDFOR and HOLDUNTIL may be given; see Sending later. |
urn:ietf:params:jmap:vacationresponse | Out-of-office replies. |
urn:ietf:params:jmap:quota | How full the person’s own mailbox is (RFC 9425): Quota/get, /changes, /query and /queryChanges, the same numbers IMAP GETQUOTA gives. |
https://nixtoffice.com/docs/server/jmap-sender-list | The senders a person allows and blocks for themselves; see JMAP sender lists. |
https://nixtoffice.com/docs/server/jmap-snooze | Snoozing a message until a time; see JMAP snooze. |
urn:ietf:params:jmap:sieve | The person’s Sieve scripts, the ones ManageSieve keeps (RFC 9661). Server-level implementation “Nixt Server Sieve”; per account, the script and name size limits, the quota, the redirect limit and every extension. |
urn:ietf:params:jmap:blob | Blob management (RFC 9404). Per account: maxSizeBlobSet (the upload limit), maxDataSources 64, supportedTypeNames Mailbox, Thread and Email, supportedDigestAlgorithms sha and sha-256. |
urn:ietf:params:jmap:mdn | Read receipts (RFC 9007): MDN/send answers a message that asked for a receipt, and MDN/parse reads one. A receipt goes from the person’s own identity, to the address the message named, and the client must mark the message $mdnsent in the same request. The organisation’s mdn.send setting says how far receipts may go. |
urn:ietf:params:jmap:websocket | url wss://<host>/jmap/ws/, supportsPush true |
urn:ietf:params:jmap:webpush-vapid | applicationServerKey, the server’s VAPID public key (RFC 9749), which an app gives its platform when it asks for a push address; see Push to phones. |
Methods
| Group | Methods |
|---|---|
| Core | Core/echo, Blob/copy |
| Mailboxes | Mailbox/get, Mailbox/changes, Mailbox/query, Mailbox/queryChanges, Mailbox/set |
| Threads | Thread/get, Thread/changes |
| Messages | Email/get, Email/changes, Email/query, Email/queryChanges, Email/set, Email/parse, Email/import, Email/copy, SearchSnippet/get |
| Identities | Identity/get, Identity/changes, Identity/set (changing an identity’s details) |
| Sending | EmailSubmission/get, EmailSubmission/changes, EmailSubmission/query, EmailSubmission/set |
| Out of office | VacationResponse/get, VacationResponse/set |
| Rules | SieveScript/get, SieveScript/set, SieveScript/query, SieveScript/validate |
| Blobs | Blob/upload, Blob/get, Blob/lookup |
| Push | PushSubscription/get, PushSubscription/set |
Push to phones
A phone app can hear about new mail while it is closed. It registers a push subscription (RFC 8620 §7.2) with PushSubscription/set, giving the https: push address its platform handed it and its encryption keys. The server then sends Web Push (RFC 8030) to that address.
- A new subscription first gets a
PushVerificationwith a code. Nothing else is sent until the app setsverificationCodeto that code. - After that, each change to the account sends a
StateChangenaming the data types that changed and their new states. Message content never travels in a push; the app fetches what it needs over JMAP. - Every push is encrypted for the device (RFC 8291,
aes128gcm) and signed with the server’s VAPID key (RFC 8292). Apps find the public key in the session, underurn:ietf:params:jmap:webpush-vapid. - Changes within a few seconds of each other become one push.
- An account can have up to 20 subscriptions. Each lasts at most 7 days; apps renew one by updating its
expires. - A push address that answers that it is gone (404 or 410) ends its subscription. A subscription also ends when the sign-in that made it ends.
- Push addresses must be public
https:hosts: the server does not send pushes into a private network.
Changes and resynchronising
Apps that keep mail on the device ask what changed since the state they last saw: JMAP’s /changes and /queryChanges methods, and IMAP’s NOTIFY. The server keeps each account’s record of changes for 30 days, and at least the last 100,000 changes, whichever is more. The operator can change both with the changes.keep_days and changes.keep_count settings.
An app that has been away for longer is told so. JMAP answers cannotCalculateChanges, and IMAP NOTIFY reports every folder as changed. The app then reads the folder list and the message list again, as it did when the account was first added. Nothing is lost: it only reads again what it already had.
Endpoints
| Path | Purpose |
|---|---|
/.well-known/jmap | The session. |
/jmap/api/ | Method calls. |
/jmap/upload/{accountId}/ | Upload. |
/jmap/download/{accountId}/{blobId}/{name}?accept={type} | Download. |
/jmap/eventsource/?types={types}&closeafter={closeafter}&ping={ping} | Push over EventSource. |
/jmap/ws/ | WebSocket, with the jmap subprotocol. |
Every endpoint needs a bearer token for the versealx-jmap audience.
CalDAV and CardDAV
| Item | Value |
|---|---|
| Methods | OPTIONS, HEAD, GET, PUT, DELETE, POST, PROPFIND, PROPPATCH, REPORT, MKCOL, MKCALENDAR, ACL |
| Discovery | /.well-known/caldav and /.well-known/carddav redirect to /dav/ |
| Access control | RFC 3744. Every resource names its owner and says what the asker may do (current-user-privilege-set), from the privileges it supports (supported-privilege-set). Its access list (acl) is read and set by its owner only. A calendar or address book is its owner’s, and reachable by whoever its owner shared it with and by a delegate who manages the owner’s calendars; everybody signed in may read the collections that lead to them. A request refused for want of a privilege names it in DAV:need-privileges. |
| Scheduling | RFC 6638, done by the server: an event with attendees saved in a calendar is carried to each of them. RFC 5546 messages; by mail, RFC 6047. |
| Sharing | RFC 3744 ACL on a calendar or an address book, and CalendarServer’s CS:share with CS:invite-reply. |
| Busy time | The scheduling outbox’s VFREEBUSY request (RFC 6638), with RFC 7953 availability. |
| Access reports | expand-property, acl-principal-prop-set, principal-match, principal-property-search and principal-search-property-set |
| Finding people | principal-property-search finds people in your own organisation who can sign in, by any part of their name or address, from two characters on, 50 at a time. |
| Calendars or address books per account | 200 of each |
| Items per collection | 100,000 |
| Octets per collection | 64 MiB |
| One item | 10 MiB |
| Recurrence instances per request | 5,000 |
| Widest time range | 10 years |
| Dates accepted | 1901 to 2100 |
| Attendees per instance | 250 |
| Results per report | 5,000 |
HTTPS
| Item | Value |
|---|---|
| Protocol | HTTP/1.1 over TLS 1.2 or 1.3 |
| Connections at once, per listener | 256 |
| Time for one request | 60 seconds |
| Request body | 256 KiB for the admin API; about 10 MiB for JMAP and DAV |
| Headers on every answer over TLS | Strict-Transport-Security: max-age=31536000, and a restrictive Content-Security-Policy |
Metrics endpoint
Plain HTTP, no authentication, /metrics, /healthz and /readyz only, 5 seconds per request. See Monitoring.
Something unclear or out of date on this page? Tell us.