---
title: "Essential Configuration"
manual: "Microsoft Exchange 365 Mailer"
version: "2.2"
permalink: "https://docs.typo3.org/permalink/oliverkroener/ok-exchange365-mailer:essential@2.2"
source: "Configuration/Essential.rst"
rendered: "2026-10-04T19:55:49+00:00"
---

# Essential Configuration {#essential}

After completing the [Azure Configuration](https://docs.typo3.org/permalink/oliverkroener/ok-exchange365-mailer:azure@2.2), you need to configure the TYPO3 extension with the values obtained from Microsoft Entra ID.

> [!WARNING]
> **Attention**
>
> The **Client ID** can be found on the overview page in Azure and **should not be confused with the Client Secret ID**. For the secret configuration, only the Secret value itself is required, not the Secret ID.

## Quick Navigation {#quick-navigation}

This page covers the complete configuration setup for the Exchange 365 TYPO3 extension:

-   [Configuration Variables](https://docs.typo3.org/permalink/oliverkroener/ok-exchange365-mailer:configuration-variables@2.2) \- Required environment variables and settings
-   [Configuration Example](https://docs.typo3.org/permalink/oliverkroener/ok-exchange365-mailer:configuration-example@2.2) \- Complete configuration example with screenshot
-   [Alternative Configuration Methods](https://docs.typo3.org/permalink/oliverkroener/ok-exchange365-mailer:alternative-configuration-methods@2.2) \- Different ways to configure the extension
-   [Testing the Configuration](https://docs.typo3.org/permalink/oliverkroener/ok-exchange365-mailer:testing-the-configuration@2.2) \- How to verify your setup works
-   [Security Considerations](https://docs.typo3.org/permalink/oliverkroener/ok-exchange365-mailer:security-considerations@2.2) \- Important security guidelines
-   [Configuration Validation](https://docs.typo3.org/permalink/oliverkroener/ok-exchange365-mailer:configuration-validation@2.2) \- Steps to validate your configuration

## Configuration Variables {#configuration-variables}

The extension reads its settings from `$GLOBALS['TYPO3_CONF_VARS']['MAIL']`. The
keys are prefixed with `transport_exchange365_` to avoid conflicts with other mail
transports. These settings are used everywhere — backend, CLI, scheduler and, unless
TypoScript overrides them, the [frontend](https://docs.typo3.org/permalink/oliverkroener/ok-exchange365-mailer:frontend@2.2).

The steps below write them as environment variables named
`TYPO3_CONF_VARS__MAIL__…`, which keeps every secret out of files that end up in
version control.

> [!IMPORTANT]
> **TYPO3 does not read** `TYPO3_CONF_VARS__…` **variables by itself.** The
> double-underscore naming is a widespread convention, but the mapping onto
> `$GLOBALS['TYPO3_CONF_VARS']` has to be done by your project — see
> [Mapping TYPO3_CONF_VARS\_\_… variables](https://docs.typo3.org/permalink/oliverkroener/ok-exchange365-mailer:env-mapping@2.2). If your project has no such mapping, use
> [In TYPO3 configuration files, reading the environment](https://docs.typo3.org/permalink/oliverkroener/ok-exchange365-mailer:config-files-from-env@2.2) instead.

1.  Set the mail transport to Exchange365Transport.

    Configure TYPO3 to use the Exchange 365 transport instead of the default SMTP transport.

    ```bash
    TYPO3_CONF_VARS__MAIL__transport=OliverKroener\\OkExchange365\\Mail\\Transport\\Exchange365Transport
    ```
1.  Configure the Tenant ID.

    Set the **Tenant ID** obtained from step 4 of the [Azure Configuration](https://docs.typo3.org/permalink/oliverkroener/ok-exchange365-mailer:azure@2.2).

    ```bash
    TYPO3_CONF_VARS__MAIL__transport_exchange365_tenantId='your-tenant-id-here'
    ```

    > [!WARNING]
    > **Attention**
    >
    > Replace `your-tenant-id-here` with the actual Tenant ID from your Azure application overview page.
1.  Configure the Client ID.

    Set the **Client ID** (Application ID) obtained from step 4 of the [Azure Configuration](https://docs.typo3.org/permalink/oliverkroener/ok-exchange365-mailer:azure@2.2).

    ```bash
    TYPO3_CONF_VARS__MAIL__transport_exchange365_clientId='your-client-id-here'
    ```

    > [!WARNING]
    > **Attention**
    >
    > Replace `your-client-id-here` with the actual Client ID from your Azure application overview page.
1.  Configure the Client Secret.

    Set the **Client Secret** value obtained from step 7 of the [Azure Configuration](https://docs.typo3.org/permalink/oliverkroener/ok-exchange365-mailer:azure@2.2).

    ```bash
    TYPO3_CONF_VARS__MAIL__transport_exchange365_clientSecret='your-client-secret-here'
    ```

    > [!WARNING]
    > **Attention**
    >
    > -   Replace `your-client-secret-here` with the actual Secret **Value** (not the Secret ID)
    > -   This is sensitive information - keep it secure and never expose it in public repositories
1.  Configure the sender email address.

    Set the email address that will be used as the sender for all emails sent through this transport.

    ```bash
    TYPO3_CONF_VARS__MAIL__transport_exchange365_fromEmail='service@your-domain.com'
    ```

    > [!WARNING]
    > **Attention**
    >
    > The email address will fall back to TYPO3's `$GLOBALS['TYPO3_CONF_VARS']['MAIL']['defaultMailFromAddress']` if not specified here.

    > [!NOTE]
    > -   Replace `service@your-domain.com` with a valid email address from your organization (it must exist in your Exchange 365 environment as **SharedMailbox or User Mailbox**)
    > -   This email address must exist in your Exchange 365 environment
    > -   The application needs permission to send emails on behalf of this address
1.  Configure the Graph sender user ID (optional).

    Set the Microsoft Graph mailbox/user ID used for the API call. This is resolved
    **separately** from the message **From** address, so you can send *as* or *on behalf of* a
    different mailbox (Send As / Send On Behalf scenarios).

    ```bash
    TYPO3_CONF_VARS__MAIL__transport_exchange365_graphSenderUserId='shared-mailbox@your-domain.com'
    ```

    > [!NOTE]
    > -   Leave empty to fall back to the message **From** address, then to `fromEmail`, then to `$GLOBALS['TYPO3_CONF_VARS']['MAIL']['defaultMailFromAddress']`
    > -   The mailbox must exist in your Exchange 365 environment and the Azure application must have `Mail.Send` permission for it
    > -   This mailbox needs *Send As* or *Send On Behalf* on the visible sender mailbox. See [Send mail from another user (Microsoft Graph)](https://learn.microsoft.com/en-us/graph/outlook-send-mail-from-other-user).
1.  Save to Sent Items (no effect on this version).

    The 2.x line posts the raw MIME message to the Graph `sendMail` endpoint.
    In that mode, Microsoft Graph always saves a copy in the *Sent Items* folder of
    the mailbox the call is made through. `transport_exchange365_saveToSentItems`
    (default `0`) is therefore ignored on this version, and the static template
    has no `saveToSentItems` constant.

## Configuration Example {#configuration-example}

Here's a complete example of all required configuration variables:

![TYPO3 configuration showing Exchange365 transport variables setup](../_Images/image16.png)

### Environment Variables (.env file) {#environment-variables-env-file}

You can configure these settings using a `.env` file in your TYPO3 root directory:

```bash
# Exchange 365 Mail Transport Configuration
TYPO3_CONF_VARS__MAIL__transport=OliverKroener\\OkExchange365\\Mail\\Transport\\Exchange365Transport
TYPO3_CONF_VARS__MAIL__transport_exchange365_tenantId='your-tenant-id-here'
TYPO3_CONF_VARS__MAIL__transport_exchange365_clientId='your-client-id-here'
TYPO3_CONF_VARS__MAIL__transport_exchange365_clientSecret='your-client-secret-here'
TYPO3_CONF_VARS__MAIL__transport_exchange365_fromEmail='service@your-domain.com'
# Optional: Send As / Send On Behalf (leave unset to use the message From)
#TYPO3_CONF_VARS__MAIL__transport_exchange365_graphSenderUserId='shared-mailbox@your-domain.com'
```

## Alternative Configuration Methods {#alternative-configuration-methods}

### Mapping `TYPO3_CONF_VARS__…` variables {#env-mapping}

If your project does not already map `TYPO3_CONF_VARS__…` environment variables,
add this loop. Double underscores become array levels, so
`TYPO3_CONF_VARS__MAIL__transport_exchange365_clientSecret` ends up in
`$GLOBALS['TYPO3_CONF_VARS']['MAIL']['transport_exchange365_clientSecret']`.

**public/typo3conf/AdditionalConfiguration.php**

```php
<?php

// Variables loaded by a dotenv library live in $_ENV, variables set by the
// web server or container in getenv(). Read both.
foreach (array_merge(getenv(), $_ENV) as $name => $value) {
    if (!is_string($name) || strpos($name, 'TYPO3_CONF_VARS__') !== 0) {
        continue;
    }
    $target = &$GLOBALS['TYPO3_CONF_VARS'];
    foreach (explode('__', substr($name, strlen('TYPO3_CONF_VARS__'))) as $segment) {
        $target = &$target[$segment];
    }
    $target = $value;
    unset($target);
}
```

### In TYPO3 configuration files, reading the environment {#config-files-from-env}

Without the mapping, set the values in
`public/typo3conf/AdditionalConfiguration.php` and read the secrets from the
environment there. Use your own variable names:

**public/typo3conf/AdditionalConfiguration.php**

```php
<?php

$env = static function (string $name): string {
    return (string)(getenv($name) ?: ($_ENV[$name] ?? ''));
};

$GLOBALS['TYPO3_CONF_VARS']['MAIL']['transport'] = \OliverKroener\OkExchange365\Mail\Transport\Exchange365Transport::class;
$GLOBALS['TYPO3_CONF_VARS']['MAIL']['transport_exchange365_tenantId'] = $env('EXCHANGE365_TENANT_ID');
$GLOBALS['TYPO3_CONF_VARS']['MAIL']['transport_exchange365_clientId'] = $env('EXCHANGE365_CLIENT_ID');
$GLOBALS['TYPO3_CONF_VARS']['MAIL']['transport_exchange365_clientSecret'] = $env('EXCHANGE365_CLIENT_SECRET');
$GLOBALS['TYPO3_CONF_VARS']['MAIL']['transport_exchange365_fromEmail'] = 'service@your-domain.com';
// Optional: distinct Graph sender mailbox (Send As / Send On Behalf).
// $GLOBALS['TYPO3_CONF_VARS']['MAIL']['transport_exchange365_graphSenderUserId'] = 'account1@your-domain.com';
```

> [!WARNING]
> Do not write the client secret as a literal into `LocalConfiguration.php`
> or `AdditionalConfiguration.php`. TYPO3 rewrites
> `LocalConfiguration.php` when settings change in the backend, and both
> files typically end up in version control and backups.

> [!NOTE]
> In the frontend, the same values can also come from TypoScript, where
> `:= getEnv(...)` reads them from the environment. See [Recommended: read the credentials from the environment](https://docs.typo3.org/permalink/oliverkroener/ok-exchange365-mailer:frontend-getenv@2.2).

## Testing the Configuration {#testing-the-configuration}

After configuring all variables, you can test the email functionality by:

1.  Sending a test email through TYPO3's mail functionality
1.  Checking the TYPO3 logs for any error messages
1.  Verifying that emails are received at the intended recipients

> [!TIP]
> Enable TYPO3's developer log to see detailed information about the email sending process and any potential issues with the Exchange 365 integration.

## Security Considerations {#security-considerations}

> [!WARNING]
> **Azure Credential Security**
>
> -   Store the `clientSecret` securely using environment variables or encrypted configuration
> -   Never commit secrets to version control systems
> -   Rotate client secrets regularly before expiration
> -   Use different Azure applications for different environments (dev/staging/prod)
> -   Monitor Azure sign-in logs for unauthorized access

> [!NOTE]
> In *System > Configuration*, the extension masks the tenant ID, client ID and
> client secret held in `TYPO3_CONF_VARS` (via a hook of the lowlevel
> configuration module). Other places, such as TypoScript, are not masked.

## Configuration Validation {#configuration-validation}

To verify your configuration is correct:

1.  **Check in backend**:

    -   Open **Admin Tools > Environment > Test Mail Setup** and send a test mail
    -   Ensure the transport is set to `Exchange365Transport` and all required fields are filled

    ![TYPO3 Environment module showing the Test Mail Setup](../_Images/image-test-mail-setup.png)
1.  **Check TYPO3 configuration**:

    ```php
    // In TYPO3 backend or debug context
    \TYPO3\CMS\Core\Utility\DebugUtility::debug($GLOBALS['TYPO3_CONF_VARS']['MAIL']);
    ```
1.  **Test email sending**:

    > ```php
    > // Test email functionality
    > $mail = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Mail\MailMessage::class);
    > $mail->to('test@example.com')
    >     ->subject('Test Email')
    >     ->text('This is a test email from TYPO3.')
    >     ->send();
    > ```
1.  **Check logs**: Monitor TYPO3 logs for authentication or sending errors.
    A failed send throws a Symfony `TransportException` (a `RuntimeException`)
    whose message names the cause, for example
    `Exchange 365 configuration missing required field: clientSecret`.

## Automated tests {#testing}

This branch is covered by the cross-version test matrix that lives on the
extension's main branch (`make test-matrix` / `make test-matrix-live` there).
For TYPO3 v10 it runs the unit and functional tests, PHPStan and the coding
standard check, sends real mail through Microsoft Graph from the CLI and from the
frontend (credentials via `:= getEnv()`), and checks in a headless browser that
the credentials are masked in the backend.
