How to create/update an account via JMAP

Your question

How to create/update an account including password, email, aliases, memberships and quota via JMAP?

Thx :slight_smile:

Ralf

Here is a complete breakdown of how to create and update an account via the JMAP API.


Creating an account (x:Account/set / create)

Requires the sysAccountCreate permission. POST to /api with urn:stalwart:jmap in the using array:

{
  "methodCalls": [
    [
      "x:Account/set",
      {
        "create": {
          "new1": {
            "@type": "User",
            "name": "alice",
            "domainId": "<Domain id>",
            "credentials": [
              {
                "@type": "Password",
                "secret": "supersecret"
              }
            ],
            "aliases": [
              { "name": "al", "domainId": "<Domain id>" }
            ],
            "memberGroupIds": ["<group id>"],
            "roles": { "@type": "User" },
            "permissions": { "@type": "Inherit" },
            "quotas": {
              "maxDiskQuota": 1073741824
            },
            "encryptionAtRest": { "@type": "Disabled" }
          }
        }
      },
      "c1"
    ]
  ],
  "using": ["urn:ietf:params:jmap:core", "urn:stalwart:jmap"]
}

Key fields:

Field Notes
@type "User" or "Group"
name Email local part (before the @)
domainId ID of the Domain object
credentials Array of Credential objects (see below)
aliases Array of EmailAlias objects: { name, domainId, enabled?, description? }
memberGroupIds Array of Account/Group IDs the user belongs to
roles { "@type": "User" }, { "@type": "Admin" }, or { "@type": "Custom", "roleIds": [...] }
permissions { "@type": "Inherit" }, "Merge", or "Replace" with enabledPermissions/disabledPermissions
quotas Map of StorageQuota keys (e.g. maxDiskQuota, maxEmails, maxMailboxes …) to UnsignedInt values
encryptionAtRest { "@type": "Disabled" } or "Aes128"/"Aes256" with a publicKey

Setting a password

The credentials field is an array. A password credential looks like:

{
  "@type": "Password",
  "secret": "plaintextpassword",
  "expiresAt": null,
  "allowedIps": []
}

Updating an account (x:Account/set / update)

Requires sysAccountUpdate. You only need to supply the fields you want to change, keyed by the account’s ID:

{
  "methodCalls": [
    [
      "x:Account/set",
      {
        "update": {
          "<account id>": {
            "aliases": [
              { "name": "newalias", "domainId": "<Domain id>" }
            ],
            "memberGroupIds": ["<group id 1>", "<group id 2>"],
            "quotas": { "maxDiskQuota": 5368709120 },
            "credentials": [
              { "@type": "Password", "secret": "newpassword" }
            ]
          }
        }
      },
      "c1"
    ]
  ],
  "using": ["urn:ietf:params:jmap:core", "urn:stalwart:jmap"]
}

StorageQuota keys (for the quotas map)

Key Meaning
maxDiskQuota Max disk space (bytes)
maxEmails Max emails
maxMailboxes Max mailboxes
maxCalendars Max calendars
maxContactCards Max contact cards
maxAppPasswords Max app passwords
maxApiKeys Max API keys
…and more See full list in the docs

CLI equivalent

# Create
stalwart-cli create Account/User \
  --field name=alice \
  --field 'domainId=<Domain id>' \
  --field 'credentials=[{"@type":"Password","secret":"mysecret"}]' \
  --field 'memberGroupIds=["<group id>"]' \
  --field 'roles={"@type":"User"}' \
  --field 'permissions={"@type":"Inherit"}' \
  --field 'quotas={"maxDiskQuota":1073741824}' \
  --field 'aliases=[{"name":"al","domainId":"<Domain id>"}]' \
  --field 'encryptionAtRest={"@type":"Disabled"}'

# Update
stalwart-cli update Account <id> --field description='new description'

Full reference: Account object docs

This is an automated reply from the Stalwart Help Bot. Other community members may follow up if this answer is incomplete or wrong.

That means I have to first search for the domain, to either get it’s ID, or create it (and get the ID).

Same for all memberships of the user, to get the group-IDs.

The domain-ID of a user is determined by the domain of it’s primary email, but he can have aliases from other domains. Can the domain-ID of a user change, when he get an email from an other domain?

Is there such a thing as the primary email of a user, or does the user just has N aliases, with name-part and domain-ID each?

Ralf

Accounts are managed through the Account object in the management API (the same objects the web UI edits), not a plain JMAP Email method. On the user variant the fields you’re asking about are: name (the local part), domainId (the primary domain’s id), credentials (a list, each a Password / AppPassword / ApiKey), aliases (a list, each an EmailAlias of enabled, name, domainId, description), memberGroupIds, roles, permissions, and quotas (a map of storage type to bytes), plus description/locale/timeZone.

On the model questions: the primary email is implicit, name@; it’s server-derived, not a separate alias entry. A user does have N aliases, each its own local part plus domainId, and aliases can be in other domains. Those alias domains do not change the account’s own domainId, which is a single field; changing the primary domain means updating domainId itself. And yes, since the schema stores ids, you’ll resolve the domain and group ids first (query Domain and Account by name) before referencing them, see the querying thread for the mechanics. Docs: stalw.art/docs/ref/object/account.