# Connect mailboxes

> A mailbox brings incoming mail into nexxus. Its attachments land in Files, it starts AI schedules, and the AI Assistant can answer it. How to connect an IMAP mailbox, including Microsoft 365, or have Postal deliver.

A mailbox in nexxus is an address whose mail nexxus reads. nexxus stores every new mail, files its attachments in a folder of your choice and hands it on: an AI schedule can react to it, or the AI Assistant answers it if you switch that on for the mailbox.

An example: Brandt & Söhne works with Microsoft 365. IT creates the mailbox `reports@example.com` and registers an app for it in Microsoft Entra. The office manager connects the mailbox in nexxus and switches on <Ui>Assistant answers mails</Ui>. From then on, project management sends a mail on Mondays saying "Please send the hours booked per project last week as Excel" and gets the table back as an attachment, worked out with their own rights. What this looks like for the person writing is described in [Ask the AI Assistant by email](/use/assistant/#ask-the-ai-assistant-by-email).

<Flow
  steps={[
    { icon: 'inbox', title: 'Mail arrives', text: 'nexxus polls the mailbox every minute, or Postal delivers at once.' },
    { icon: 'user-cog', title: 'Stored', text: 'As the mailbox\'s service account, without duplicates.', tone: 'cyan' },
    { icon: 'folder-input', title: 'Attachments filed', text: 'In the folder you chose. Without a folder they are only listed.', tone: 'lavender' },
    { icon: 'sparkles', title: 'Processed further', text: 'An AI schedule takes it, or the AI Assistant answers.' },
  ]}
  caption="Each mail is handled once: if a schedule takes it, the AI Assistant does not answer."
/>

## Before you start

- You have the system role ADMIN in nexxus. The page <Ui>Mailboxes</Ui> opens for administrators only.
- There is a **service account** the mailbox works as. Filed attachments belong to it, and its roles decide which folders it may file into. How to create one is described in [Service accounts](/setup/invite-users/#service-accounts).
- You know how the mail comes in:
  - **IMAP with a password**: server, port, username and password of the mailbox.
  - **Microsoft 365**: Exchange Online takes no password over IMAP. The mailbox signs in through an app registration in Microsoft Entra. Someone who may register apps in Entra and grant rights in Exchange Online PowerShell sets this up, usually your IT. The steps are [below](#microsoft-365-sign-in-through-an-app-registration).
  - **Postal**: a Postal server delivers every mail directly. You need access to its routing.

## Create a mailbox

<Steps>

1. Open <MenuPath to="Administration > Content & automation > Mailboxes" /> and click <Ui>Create mailbox</Ui>. The page <Ui>New mailbox</Ui> opens in edit mode.

2. In the section <Ui>Connection</Ui>, enter a <Ui>Name</Ui> such as "Inquiries" and choose the <Ui>Kind</Ui>: <Ui>IMAP mailbox</Ui> or <Ui>Forwarded by Postal</Ui>. For Postal, continue [further down](#postal-delivery-instead-of-polling).

3. Under <Ui>Sign-in</Ui>, choose how the mailbox signs in:

   - <Ui>Username and password</Ui>: enter <Ui>Server</Ui>, <Ui>Port</Ui>, <Ui>Username</Ui> and <Ui>Password</Ui>. Usual are port 993 with <Ui>SSL/TLS (IMAPS)</Ui> and port 143 with <Ui>STARTTLS</Ui>, switched with <Ui>Encryption</Ui>. nexxus never polls a mailbox unencrypted.
   - <Ui>Microsoft 365 (app registration)</Ui>: nexxus fills in the <Ui>Server</Ui> `outlook.office365.com` if the field is empty. The <Ui>Username</Ui> is the mailbox address. You also enter <Ui>Directory (tenant) ID</Ui>, <Ui>Application (client) ID</Ui> and <Ui>Client secret</Ui> from Entra, see [below](#step-3-enter-it-in-nexxus).

   <Ui>IMAP folder</Ui> is the folder nexxus reads. Left empty, it is `INBOX`.

4. In the section <Ui>Processing</Ui>:

   - <Ui>Receiving</Ui> is set to <Ui>Paused</Ui> for a new mailbox. Leave it that way until the connection test has passed.
   - Choose the <Ui>Service account</Ui>. The list shows only accounts of the account type service account.
   - Use <Ui>Choose folder</Ui> to pick an <Ui>Attachment folder</Ui> if attachments should land in Files. Without a folder nexxus only lists the attachments (<Ui>none, attachments are only listed</Ui>).

5. In the section <Ui>AI assistant</Ui>, switch on <Ui>Assistant answers mails</Ui> if the AI Assistant should answer requests sent to this mailbox. Below it you set <Ui>Requests per person and hour</Ui>, between 1 and 100, with 5 as the default. What happens then is described in [Ask the AI Assistant by email](/use/assistant/#ask-the-ai-assistant-by-email).

6. Click <Ui>Save</Ui>. The message <Ui>Mailbox created</Ui> confirms it, and the page shows the mailbox in read view.

7. Click <Ui>Test connection</Ui>. nexxus signs in with the stored data without fetching anything. If it works, you see something like "Connection ok: 12 mails, 3 unread". Otherwise you see „Verbindung fehlgeschlagen:“ (connection failed) and the reason, see [When something goes wrong](#when-something-goes-wrong).

8. Click <Ui>Edit</Ui>, set <Ui>Receiving</Ui> to <Ui>Active</Ui> and click <Ui>Save</Ui>.

9. Once for the whole installation, switch on regular polling: open <MenuPath to="Administration > Operations > Maintenance > Cron Jobs" /> and set the job `MAILBOX_POLLER` to <Ui>Active</Ui>. nexxus creates it switched off. As long as it is off, only what you fetch with <Ui>Poll now</Ui> arrives.

</Steps>

<Ui>Poll now</Ui> fetches new mail at once, even while the mailbox is paused, and reports something like <Ui>No new mails</Ui> or "2 new mails received". Under <Ui>Received mails</Ui> the page shows the last 25 mails of the mailbox. Clicking a row opens the recipients, the attachments with a link into Files, the text and, if the AI Assistant was involved, what it did with the mail.

## Microsoft 365: sign-in through an app registration

Exchange Online refuses an IMAP sign-in with username and password. A mailbox at Microsoft 365 therefore signs in as an app: nexxus uses the directory ID, the application ID and the client secret to get an access token from Microsoft and signs in over IMAP with it. Nobody has to sign in for this, and no personal password is stored in nexxus.

The app needs two things for this: in Entra the application permission **IMAP.AccessAsApp** with admin consent, and in Exchange Online the right to exactly this mailbox. Without the second, it can sign in but cannot open a mailbox.

### Step 1: register the app in Microsoft Entra

You do these steps in the Microsoft Entra admin center.

<Steps>

1. Open `https://entra.microsoft.com` and go to **Entra ID** › **App registrations** › **New registration**. Give the app a name your IT recognises, such as "nexxus mailbox". Under **Supported account types**, choose **Single tenant only**. This app needs no redirect URI.

2. Open **Certificates & secrets** › **Client secrets** › **New client secret**. Copy the **Value** right away: Microsoft shows it only once. nexxus needs the value, not the **Secret ID**. Note the expiry date. Once the secret has expired, nexxus stops polling the mailbox.

3. Open **API permissions** › **Add a permission** › **APIs my organization uses**, search for **Office 365 Exchange Online**, choose **Application permissions**, tick **IMAP.AccessAsApp** and click **Add permissions**.

4. On the same page, click **Grant admin consent** for your directory. The permission must then show as granted.

5. On the **Overview** page, copy the **Application (client) ID** and the **Directory (tenant) ID**.

6. Open **Entra ID** › **Enterprise applications**, choose the same app and copy the **Object ID** from its **Overview** page. Careful: this is a different Object ID from the one on the app registration's page. With the wrong one, the sign-in fails later.

</Steps>

### Step 2: give the app the mailbox

You do these steps in Exchange Online PowerShell, with an account that may grant rights in Exchange Online. First you register the app as a service principal in Exchange, then you give it the mailbox:

```powershell
Install-Module -Name ExchangeOnlineManagement
Connect-ExchangeOnline -Organization <Directory (tenant) ID>

New-ServicePrincipal -AppId <Application (client) ID> -ObjectId <Object ID of the enterprise application> -DisplayName "nexxus mailbox"
$sp = Get-ServicePrincipal -Identity "nexxus mailbox"
Add-MailboxPermission -Identity <mailbox address> -User $sp.Identity -AccessRights FullAccess
```

If IMAP is switched off for the mailbox, switch it on:

```powershell
Set-CASMailbox -Identity <mailbox address> -ImapEnabled $true
```

This way the app reaches only the mailboxes you give it with `Add-MailboxPermission`, not every mailbox of your organisation. Microsoft describes the procedure in [Authenticate an IMAP, POP or SMTP connection using OAuth](https://learn.microsoft.com/en-us/exchange/client-developer/legacy-protocols/how-to-authenticate-an-imap-pop-smtp-application-by-using-oauth), in the section on the client credentials flow.

### Step 3: enter it in nexxus

<Steps>

1. Create the mailbox as described [above](#create-a-mailbox), with the <Ui>Kind</Ui> <Ui>IMAP mailbox</Ui> and the <Ui>Sign-in</Ui> <Ui>Microsoft 365 (app registration)</Ui>. The field <Ui>Password</Ui> disappears, and the three fields for Entra appear instead.

2. Enter:

   | Field | Value |
   |---|---|
   | <Ui>Server</Ui> | `outlook.office365.com`, filled in if the field was empty. <Ui>Port</Ui> 993 with <Ui>SSL/TLS (IMAPS)</Ui> |
   | <Ui>Username</Ui> | The mailbox address, such as `reports@example.com` |
   | <Ui>Directory (tenant) ID</Ui> | The **Directory (tenant) ID**. The directory's domain works too, such as `company.onmicrosoft.com` |
   | <Ui>Application (client) ID</Ui> | The **Application (client) ID** |
   | <Ui>Client secret</Ui> | The **Value** of the client secret |

3. Click <Ui>Save</Ui> and then <Ui>Test connection</Ui>. If Microsoft refuses, nexxus names the reason in German, see [When something goes wrong](#when-something-goes-wrong).

</Steps>

nexxus never shows the stored secret again. When you edit the mailbox, the field reads <Ui>unchanged</Ui>: leave it empty and nexxus keeps the secret, enter a new one and it replaces the old. This is also how you swap an expired secret.

## Postal: delivery instead of polling

With a Postal server, nexxus polls nothing. Postal sends every mail at once to a receiving URL of nexxus and signs every delivery. nexxus accepts only deliveries with a valid signature.

<Steps>

1. Create the mailbox with the <Ui>Kind</Ui> <Ui>Forwarded by Postal</Ui>. Server, username and password do not exist then.

2. <Ui>Postal key (JWKS)</Ui> is the address where your Postal server publishes its signing keys. It must start with `https://`. Left empty, the <Ui>Server default</Ui> applies.

3. Choose service account and folder as above and click <Ui>Save</Ui>. Only now is the <Ui>Receiving URL</Ui> created. Copy it with <Ui>Copy URL</Ui>.

4. In Postal, create an HTTP endpoint under **Routing** with this URL, with the encoding **Sent in the body as JSON** and the format **Delivered as the raw message**, and point the route for the receiving address at it.

5. <Ui>Test connection</Ui> loads the keys from Postal and reports something like <Ui>Postal key loaded (1). Signed deliveries are accepted.</Ui>

</Steps>

<Ui>Create new URL</Ui> replaces the receiving URL, for example if it got into the wrong hands. The old one stops accepting mail at once, so update the route in Postal right after. A Postal mailbox set to <Ui>Paused</Ui> accepts no deliveries.

## What happens behind the scenes

- **Polling.** While the job `MAILBOX_POLLER` is active, nexxus polls all active IMAP mailboxes every minute, up to 25 mails per mailbox and round. It reads only unread mails in the <Ui>IMAP folder</Ui> and marks each one as read once it is stored. If nexxus stops in between, the mail stays unread and comes again with the next poll. A mail whose Message-ID the mailbox already knows is not stored a second time.
- **Service account.** Every mail is stored and filed as the service account. If it is deleted or no longer a service account, nexxus polls nothing and writes the reason under <Ui>Error</Ui>.
- **Attachments.** With a folder they become documents in Files, without one they are only listed. nexxus lists attachments over 25 MB but does not read them.
- **What comes next.** Every new mail goes to the active AI schedules with the trigger <Ui>On new email</Ui> for this mailbox whose filters match. If none takes it and <Ui>Assistant answers mails</Ui> is on, nexxus checks whether the AI Assistant answers it.
- **Credentials.** nexxus stores password and client secret encrypted only and never shows them again. nexxus keeps the access token from Microsoft in memory and fetches a new one shortly before it expires. If Exchange Online refuses the sign-in, nexxus drops the token and fetches a fresh one on the next attempt.
- **Deleting.** A deleted mailbox accepts nothing any more, and a stored password is discarded. Received mails are kept.

:::note[For self-hosters]
Scheduled jobs run only when `app.disableCronJobs` is `false`, which the production profile sets. The interval between polls is `communication.mailbox.pollDelayMs` (60000), the number of mails per round `communication.mailbox.maxMailsPerPoll` (25). The default for <Ui>Postal key (JWKS)</Ui> comes from `communication.mailbox.postal.defaultJwksUrl` (environment variable `POSTAL_JWKS_URL`). For Microsoft 365, nexxus needs outgoing connections to `login.microsoftonline.com` and `outlook.office365.com`.
:::

## When something goes wrong

Errors of the connection test follow „Verbindung fehlgeschlagen:“. Errors of polling show in the field <Ui>Error</Ui> and at the top of the page: <Ui>The last poll failed: ...</Ui> The server messages exist in German only.

| Message | What to do |
|---|---|
| „Microsoft 365 lehnt den geheimen Clientschlüssel ab. Eingetragen sein muss sein Wert, nicht die ID des Geheimnisses.“ (Microsoft 365 refuses the client secret; it must be its value, not the secret's ID) | Enter the **Value** under <Ui>Client secret</Ui>, not the **Secret ID**. If the value can no longer be seen, create a new secret in Entra. |
| „Der geheime Clientschlüssel ist abgelaufen. Bitte in Entra einen neuen anlegen und hier eintragen.“ (the client secret has expired) | Create a new secret under **Certificates & secrets** and enter its value. |
| „Eine App mit dieser Anwendungs-ID (Client) gibt es in diesem Verzeichnis nicht.“ (no app with this application ID in this directory) | Check <Ui>Application (client) ID</Ui> and <Ui>Directory (tenant) ID</Ui>. The app must be registered in this directory. |
| „Microsoft kennt diese Verzeichnis-ID (Tenant) nicht.“ (Microsoft does not know this directory ID) | Enter the **Directory (tenant) ID** from the app's overview page, or the directory's domain. |
| „Exchange Online hat die IMAP-Anmeldung abgelehnt: Der App fehlt die Anwendungsberechtigung IMAP.AccessAsApp (Office 365 Exchange Online) mit Administratorzustimmung.“ (the app lacks the application permission IMAP.AccessAsApp with admin consent) | Add the permission and grant consent, see step 1, items 3 and 4. A delegated permission is not enough. |
| „Exchange Online hat die IMAP-Anmeldung abgelehnt. Hat die App Zugriff auf dieses Postfach (Dienstprinzipal in Exchange mit New-ServicePrincipal, Recht mit Add-MailboxPermission), und ist IMAP für das Postfach eingeschaltet?“ (Exchange Online refused the sign-in; does the app have access to this mailbox, and is IMAP on?) | Do step 2. Check that `New-ServicePrincipal` got the Object ID of the **enterprise application** and that IMAP is on for the mailbox. |
| „Bei Microsoft 365 ist der Benutzername die Adresse des Postfachs.“ (with Microsoft 365 the username is the mailbox address) | Enter the full address under <Ui>Username</Ui>. |
| „Ohne Passwort kann das Postfach nicht aktiv sein.“ or „Ohne geheimen Clientschlüssel kann das Postfach nicht aktiv sein.“ (without a password or client secret the mailbox cannot be active) | Enter the password or secret before setting <Ui>Receiving</Ui> to <Ui>Active</Ui>. |
| „Das Dienstkonto ist gelöscht oder kein Dienstkonto mehr.“ (the service account is deleted or no longer a service account) | Choose another <Ui>Service account</Ui>, or set the account type of the old one back to <Ui>Service account</Ui>. |
| „Die Adresse des Postal-Schlüssels (JWKS) muss mit https:// beginnen.“ (the Postal key address must start with https://) | Enter the HTTPS address or leave the field empty. |
| The test passes, but nothing arrives | The job `MAILBOX_POLLER` is off, or <Ui>Receiving</Ui> is set to <Ui>Paused</Ui>. Or the new mails have already been read: nexxus fetches unread mails only. |

## Next steps

<CardGrid>
  <LinkCard title="Ask the AI Assistant by email" description="Who gets an answer, what it looks like and where you see the state of every mail." href="/use/assistant/#ask-the-ai-assistant-by-email" />
  <LinkCard title="Service accounts" description="Create the account a mailbox works as." href="/setup/invite-users/#service-accounts" />
  <LinkCard title="Files" description="Where filed attachments land and who sees them." href="/use/files/" />
</CardGrid>