# Extending: custom transport

> Add a mail provider BooleanSMTP does not ship, by implementing TransportContract and registering it on the boolean_smtp_transports filter.

A transport is anything that can configure PHPMailer for a provider and describe its own settings
to the admin UI. Every built-in provider — SendGrid, Amazon SES, Custom SMTP, and the rest — is one
implementation of `TransportContract`; a transport you register yourself is no different.

## The contract

```php
namespace BooleanSmtp\Contracts;

interface TransportContract
{
    public function getDriver(): string;
    public function getName(): string;
    public function configure(\PHPMailer\PHPMailer\PHPMailer $phpmailer, array $settings): void;
    public function validateSettings(array $settings): array;
    public function getSettingsSchema(): array;
    public function getDeliveryModes(): array;
    public function getSmtpPresets(): array;
    public function getValidationRules(): array;
}
```

| Method | Returns | Purpose |
| --- | --- | --- |
| `getDriver()` | `string` | The unique driver slug used everywhere else — connection records, `wp-config` constants, REST routes. |
| `getName()` | `string` | The display name shown in the admin UI. |
| `configure($phpmailer, $settings)` | `void` | Set whatever PHPMailer needs — host, port, API driver — from the decrypted connection settings. |
| `validateSettings($settings)` | `array<string, string>` | Validation errors keyed by field name; empty when valid. |
| `getSettingsSchema()` | `array<string, array{type, label, required, default?}>` | Field definitions the admin UI's connection form renders from. |
| `getDeliveryModes()` | `array<string, string>` | Delivery modes this transport offers, e.g. `['smtp' => 'SMTP', 'api' => 'HTTP API']`. |
| `getSmtpPresets()` | `array<string, array{host, port, encryption, label}>` | Presets shown in the settings dropdown, when relevant. |
| `getValidationRules()` | `array<string, string>` | Pipe-delimited rule strings, e.g. `['api_key' => 'required\|string']`. |

## Register it

```php
namespace App\Services\Transport;

use BooleanSmtp\Contracts\TransportContract;

class CustomTransport implements TransportContract {
    public function getDriver(): string { return 'custom'; }
    public function getName(): string { return 'My Custom Provider'; }
    public function configure( \PHPMailer\PHPMailer\PHPMailer $phpmailer, array $settings ): void {
        $phpmailer->isSMTP();
        $phpmailer->Host = 'smtp.example.com';
        $phpmailer->Username = $settings['username'] ?? '';
        $phpmailer->Password = $settings['password'] ?? '';
    }
    public function validateSettings( array $settings ): array { return []; }
    public function getSettingsSchema(): array { return []; }
    public function getDeliveryModes(): array { return [ 'smtp' => 'SMTP' ]; }
    public function getSmtpPresets(): array { return []; }
    public function getValidationRules(): array { return []; }
}
```

```php
add_filter( 'boolean_smtp_transports', function ( array $transports ): array {
    $transports['custom'] = \App\Services\Transport\CustomTransport::class;
    return $transports;
} );
```

Once registered, `custom` behaves like any built-in driver: it appears in `GET /transports`, a
connection can be created with `"driver": "custom"`, and its credentials can be pinned with
`BOOLEANSMTP_CUSTOM_{KEY}` [constants](/constants/) — the naming rule is generic, driven by
whatever field names your `getSettingsSchema()` declares.

## Next steps

- [`boolean_smtp_transports`](/hooks/boolean_smtp_transports/) — the registration filter itself.
- [REST API: transports](/rest-api/#transports) — `GET /transports/{driver}` returns exactly what
  your `getSettingsSchema()` and `getValidationRules()` produce.
- [Alert channel](/extending/alert-channel/) — the equivalent contract for notification destinations.
