Modern PHP SDK for EmailEngine - the self-hosted email gateway that provides a REST API for IMAP and SMTP operations.
- PHP 8.1 or higher
- Composer
- EmailEngine instance
composer require postalsys/emailengine-phpuse Postalsys\EmailEnginePhp\EmailEngine;
$client = new EmailEngine(
accessToken: 'your-access-token',
baseUrl: 'http://localhost:3000',
);
// List all accounts
$accounts = $client->accounts->list();
// Send an email
$result = $client->messages->submit('account-id', [
'from' => ['name' => 'Sender', 'address' => 'sender@example.com'],
'to' => [['name' => 'Recipient', 'address' => 'recipient@example.com']],
'subject' => 'Hello from EmailEngine PHP SDK',
'text' => 'This is a test email.',
'html' => '<p>This is a test email.</p>',
]);$client = new EmailEngine(
accessToken: 'your-access-token', // Required: API access token
baseUrl: 'http://localhost:3000', // EmailEngine base URL (default: localhost:3000)
serviceSecret: 'your-service-secret', // For hosted authentication URLs
redirectUrl: 'http://your-app/callback', // Default redirect URL for auth
timeout: 30, // Request timeout in seconds
);$client = EmailEngine::fromOptions([
'access_token' => 'your-access-token',
'ee_base_url' => 'http://localhost:3000',
'service_secret' => 'your-service-secret',
'redirect_url' => 'http://your-app/callback',
]);The SDK provides access to all EmailEngine API endpoints through resource classes:
| Resource | Description |
|---|---|
$client->accounts |
Account management (CRUD, sync, reconnect) |
$client->messages |
Message operations (list, read, send, search) |
$client->mailboxes |
Mailbox management (create, rename, delete) |
$client->outbox |
Queued message management |
$client->settings |
System and webhook settings |
$client->tokens |
Access token management |
$client->templates |
Email template management |
$client->gateways |
SMTP gateway configuration |
$client->oauth2 |
OAuth2 application management |
$client->webhooks |
Webhook route management |
$client->stats |
System statistics and utilities |
$client->blocklists |
Blocklist management |
// Create a new account
$account = $client->accounts->create([
'account' => 'my-account',
'name' => 'John Doe',
'email' => 'john@example.com',
'imap' => [
'host' => 'imap.example.com',
'port' => 993,
'secure' => true,
'auth' => ['user' => 'john@example.com', 'pass' => 'password'],
],
'smtp' => [
'host' => 'smtp.example.com',
'port' => 465,
'secure' => true,
'auth' => ['user' => 'john@example.com', 'pass' => 'password'],
],
]);
// Get account info
$info = $client->accounts->get('my-account');
echo "Account state: " . $info['state'];
// List all accounts
$accounts = $client->accounts->list(['page' => 0, 'pageSize' => 20]);
// Force reconnection
$client->accounts->reconnect('my-account');
// Delete account
$client->accounts->delete('my-account');// List messages in INBOX
$messages = $client->messages->list('my-account', [
'path' => 'INBOX',
'pageSize' => 50,
]);
// Get message details
$message = $client->messages->get('my-account', 'message-id', [
'textType' => 'html',
]);
// Search messages
$results = $client->messages->search('my-account', [
'path' => 'INBOX',
'search' => [
'unseen' => true,
'from' => 'important@example.com',
],
]);
// Update message flags
$client->messages->update('my-account', 'message-id', [
'flags' => ['add' => ['\\Seen', '\\Flagged']],
]);
// Move message
$client->messages->move('my-account', 'message-id', 'Archive');
// Delete message
$client->messages->delete('my-account', 'message-id');
// Bulk operations
$client->messages->bulkUpdate('my-account', [
'path' => 'INBOX',
'messages' => ['msg-1', 'msg-2', 'msg-3'],
'flags' => ['add' => ['\\Seen']],
]);// Basic email
$result = $client->messages->submit('my-account', [
'from' => ['name' => 'Sender', 'address' => 'sender@example.com'],
'to' => [['name' => 'Recipient', 'address' => 'recipient@example.com']],
'cc' => [['address' => 'cc@example.com']],
'subject' => 'Test Subject',
'text' => 'Plain text content',
'html' => '<p>HTML content</p>',
]);
// With attachments
$result = $client->messages->submit('my-account', [
'from' => ['address' => 'sender@example.com'],
'to' => [['address' => 'recipient@example.com']],
'subject' => 'Email with attachment',
'text' => 'Please see attached.',
'attachments' => [
[
'filename' => 'document.pdf',
'content' => base64_encode(file_get_contents('document.pdf')),
'contentType' => 'application/pdf',
],
],
]);
// Using templates
$result = $client->messages->submit('my-account', [
'to' => [['name' => 'John', 'address' => 'john@example.com']],
'template' => 'welcome-email',
'render' => [
'name' => 'John',
'company' => 'Acme Inc',
],
]);
// With idempotency key (prevents duplicates)
$result = $client->messages->submit('my-account', [
'to' => [['address' => 'recipient@example.com']],
'subject' => 'Important email',
'text' => 'Content',
], [
'idempotencyKey' => 'unique-key-12345',
]);
// Scheduled send
$result = $client->messages->submit('my-account', [
'to' => [['address' => 'recipient@example.com']],
'subject' => 'Scheduled email',
'text' => 'This will be sent later',
'sendAt' => '2024-12-25T10:00:00Z',
]);// Download and stream an attachment directly to the browser
$client->download("/v1/account/my-account/attachment/AAAAAQAABRQ");// List mailboxes
$mailboxes = $client->mailboxes->list('my-account', ['counters' => true]);
// Create mailbox
$client->mailboxes->create('my-account', 'INBOX/Projects');
// Rename mailbox
$client->mailboxes->rename('my-account', 'INBOX/OldName', 'INBOX/NewName');
// Delete mailbox
$client->mailboxes->delete('my-account', 'INBOX/ToDelete');
// Subscribe/unsubscribe
$client->mailboxes->subscribe('my-account', 'Archive');
$client->mailboxes->unsubscribe('my-account', 'Spam');// Get webhook settings
$webhooks = $client->settings->getWebhooks();
// Configure webhooks
$client->settings->setWebhooks([
'enabled' => true,
'url' => 'https://your-app.com/webhooks',
'events' => ['messageNew', 'messageUpdated', 'messageSent'],
'headers' => ['Received', 'List-ID'],
'text' => 2048, // Include first 2KB of text content
]);Generate URLs for EmailEngine's hosted authentication form:
$client = new EmailEngine(
accessToken: 'your-token',
baseUrl: 'http://localhost:3000',
serviceSecret: 'your-service-secret',
redirectUrl: 'http://your-app/auth-callback',
);
// Generate auth URL
$authUrl = $client->getAuthenticationUrl([
'account' => null, // null = auto-generate account ID
'name' => 'User Name',
'email' => 'user@example.com',
]);
// Redirect user to $authUrl
header('Location: ' . $authUrl);// List queued messages
$queue = $client->outbox->list(['account' => 'my-account']);
// Get queued message details
$item = $client->outbox->get('queue-id');
// Cancel scheduled message
$client->outbox->cancel('queue-id');// Get system stats
$stats = $client->stats->get();
echo "EmailEngine version: " . $stats['version'];
echo "Connected accounts: " . $stats['connections']['connected'];
// Auto-discover email settings
$config = $client->stats->autoconfig('user@gmail.com');The SDK throws specific exceptions for different error types:
use Postalsys\EmailEnginePhp\Exceptions\AuthenticationException;
use Postalsys\EmailEnginePhp\Exceptions\AuthorizationException;
use Postalsys\EmailEnginePhp\Exceptions\NotFoundException;
use Postalsys\EmailEnginePhp\Exceptions\ValidationException;
use Postalsys\EmailEnginePhp\Exceptions\RateLimitException;
use Postalsys\EmailEnginePhp\Exceptions\ServerException;
use Postalsys\EmailEnginePhp\Exceptions\EmailEngineException;
try {
$account = $client->accounts->get('unknown-account');
} catch (NotFoundException $e) {
echo "Account not found: " . $e->getMessage();
echo "Error code: " . $e->getErrorCode();
} catch (AuthenticationException $e) {
echo "Invalid API token";
} catch (ValidationException $e) {
echo "Validation error: " . $e->getMessage();
print_r($e->getDetails());
} catch (RateLimitException $e) {
echo "Rate limited. Retry after: " . $e->getRetryAfter() . " seconds";
} catch (EmailEngineException $e) {
echo "API error: " . $e->getMessage();
}For endpoints not covered by resource classes:
// GET request
$response = $client->request('GET', '/v1/some-endpoint', query: ['param' => 'value']);
// POST request
$response = $client->request('POST', '/v1/some-endpoint', data: ['key' => 'value']);
// With custom headers
$response = $client->request('POST', '/v1/some-endpoint',
data: ['key' => 'value'],
headers: ['X-Custom-Header' => 'value']
);# Install dependencies
make install
# Run unit tests
make test
# Run tests with coverage
make test-coverage
# Run static analysis
make phpstan
# Check code style
make lintTest across multiple PHP versions using Docker:
# Run unit tests on PHP 8.3
make docker-test
# Run tests on all PHP versions (8.1, 8.2, 8.3, 8.4)
make docker-test-all
# Run integration tests with real EmailEngine
make docker-integrationIntegration tests run against a real EmailEngine instance:
# Start EmailEngine and Redis
make docker-up
# Run integration tests (auto-generates access token)
make docker-integration
# View EmailEngine logs
make docker-logs
# Stop services
make docker-downNote: EmailEngine without a license suspends workers after 15 minutes. Integration tests are designed to complete within this time window. If you need more time, restart EmailEngine:
docker compose restart emailengineTo run integration tests against your own EmailEngine instance:
# Generate a token using EmailEngine CLI
emailengine tokens issue -d "Test" -s "*" --dbs.redis="redis://localhost:6379"
# Run tests with your token
EMAILENGINE_ACCESS_TOKEN="your-token" \
EMAILENGINE_BASE_URL="http://localhost:3000" \
./vendor/bin/phpunit --testsuite integrationThe SDK maintains backward compatibility with the old API:
// Old way (still works, but deprecated)
use EmailEnginePhp\EmailEngine;
$ee = new EmailEngine([
'access_token' => 'token',
'ee_base_url' => 'http://localhost:3000',
'service_secret' => 'secret',
'redirect_url' => 'http://callback.url',
]);
$ee->get_webhook_settings();
$ee->set_webhook_settings(['enabled' => true]);
$ee->get_authentication_url(['account' => null]);MIT License - see LICENSE file.
- EmailEngine - Self-hosted email gateway
- EmailEngine Documentation - API reference
- GitHub Repository