2026-04-14 14:55:39 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
namespace Tests\E2E\Services\Project;
|
|
|
|
|
|
|
|
|
|
use Tests\E2E\Client;
|
2026-04-14 15:09:37 +00:00
|
|
|
use Utopia\Database\Helpers\ID;
|
2026-04-14 14:55:39 +00:00
|
|
|
|
|
|
|
|
trait SMTPBase
|
|
|
|
|
{
|
|
|
|
|
// Update SMTP status tests
|
|
|
|
|
|
|
|
|
|
public function testUpdateSMTPStatusEnable(): void
|
|
|
|
|
{
|
2026-04-20 12:42:52 +00:00
|
|
|
$response = $this->updateSMTP(
|
|
|
|
|
senderName: 'Test Sender',
|
|
|
|
|
senderEmail: 'sender@example.com',
|
|
|
|
|
host: 'maildev',
|
|
|
|
|
port: 1025,
|
|
|
|
|
enabled: true,
|
|
|
|
|
);
|
2026-04-14 14:55:39 +00:00
|
|
|
|
|
|
|
|
$this->assertSame(200, $response['headers']['status-code']);
|
|
|
|
|
$this->assertNotEmpty($response['body']['$id']);
|
|
|
|
|
$this->assertSame(true, $response['body']['smtpEnabled']);
|
|
|
|
|
|
|
|
|
|
// Cleanup
|
2026-04-20 12:42:52 +00:00
|
|
|
$this->updateSMTP(enabled: false);
|
2026-04-14 14:55:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testUpdateSMTPStatusDisable(): void
|
|
|
|
|
{
|
2026-04-20 12:42:52 +00:00
|
|
|
$this->updateSMTP(
|
|
|
|
|
senderName: 'Test Sender',
|
|
|
|
|
senderEmail: 'sender@example.com',
|
|
|
|
|
host: 'maildev',
|
|
|
|
|
port: 1025,
|
|
|
|
|
enabled: true,
|
|
|
|
|
);
|
2026-04-14 14:55:39 +00:00
|
|
|
|
2026-04-20 12:42:52 +00:00
|
|
|
$response = $this->updateSMTP(enabled: false);
|
2026-04-14 14:55:39 +00:00
|
|
|
|
|
|
|
|
$this->assertSame(200, $response['headers']['status-code']);
|
|
|
|
|
$this->assertNotEmpty($response['body']['$id']);
|
|
|
|
|
$this->assertSame(false, $response['body']['smtpEnabled']);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testUpdateSMTPStatusEnableIdempotent(): void
|
|
|
|
|
{
|
2026-04-20 12:42:52 +00:00
|
|
|
$first = $this->updateSMTP(
|
|
|
|
|
senderName: 'Test Sender',
|
|
|
|
|
senderEmail: 'sender@example.com',
|
|
|
|
|
host: 'maildev',
|
|
|
|
|
port: 1025,
|
|
|
|
|
enabled: true,
|
|
|
|
|
);
|
2026-04-14 14:55:39 +00:00
|
|
|
$this->assertSame(200, $first['headers']['status-code']);
|
|
|
|
|
$this->assertSame(true, $first['body']['smtpEnabled']);
|
|
|
|
|
|
2026-04-20 12:42:52 +00:00
|
|
|
$second = $this->updateSMTP(enabled: true);
|
2026-04-14 14:55:39 +00:00
|
|
|
$this->assertSame(200, $second['headers']['status-code']);
|
|
|
|
|
$this->assertSame(true, $second['body']['smtpEnabled']);
|
|
|
|
|
|
|
|
|
|
// Cleanup
|
2026-04-20 12:42:52 +00:00
|
|
|
$this->updateSMTP(enabled: false);
|
2026-04-14 14:55:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testUpdateSMTPStatusDisableIdempotent(): void
|
|
|
|
|
{
|
2026-04-20 12:42:52 +00:00
|
|
|
$first = $this->updateSMTP(
|
|
|
|
|
senderName: 'Test Sender',
|
|
|
|
|
senderEmail: 'sender@example.com',
|
|
|
|
|
host: 'maildev',
|
|
|
|
|
port: 1025,
|
|
|
|
|
enabled: false,
|
|
|
|
|
);
|
2026-04-14 14:55:39 +00:00
|
|
|
$this->assertSame(200, $first['headers']['status-code']);
|
|
|
|
|
$this->assertSame(false, $first['body']['smtpEnabled']);
|
|
|
|
|
|
2026-04-20 12:42:52 +00:00
|
|
|
$second = $this->updateSMTP(enabled: false);
|
2026-04-14 14:55:39 +00:00
|
|
|
$this->assertSame(200, $second['headers']['status-code']);
|
|
|
|
|
$this->assertSame(false, $second['body']['smtpEnabled']);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testUpdateSMTPStatusResponseModel(): void
|
|
|
|
|
{
|
2026-04-20 12:42:52 +00:00
|
|
|
$response = $this->updateSMTP(
|
|
|
|
|
senderName: 'Test Sender',
|
|
|
|
|
senderEmail: 'sender@example.com',
|
|
|
|
|
host: 'maildev',
|
|
|
|
|
port: 1025,
|
|
|
|
|
enabled: true,
|
|
|
|
|
);
|
2026-04-14 14:55:39 +00:00
|
|
|
|
|
|
|
|
$this->assertSame(200, $response['headers']['status-code']);
|
|
|
|
|
$this->assertArrayHasKey('$id', $response['body']);
|
|
|
|
|
$this->assertArrayHasKey('name', $response['body']);
|
|
|
|
|
$this->assertArrayHasKey('smtpEnabled', $response['body']);
|
|
|
|
|
$this->assertArrayHasKey('smtpSenderName', $response['body']);
|
|
|
|
|
$this->assertArrayHasKey('smtpSenderEmail', $response['body']);
|
2026-04-20 09:47:06 +00:00
|
|
|
$this->assertArrayHasKey('smtpReplyToEmail', $response['body']);
|
|
|
|
|
$this->assertArrayHasKey('smtpReplyToName', $response['body']);
|
2026-04-14 14:55:39 +00:00
|
|
|
$this->assertArrayHasKey('smtpHost', $response['body']);
|
|
|
|
|
$this->assertArrayHasKey('smtpPort', $response['body']);
|
|
|
|
|
$this->assertArrayHasKey('smtpUsername', $response['body']);
|
|
|
|
|
$this->assertArrayHasKey('smtpPassword', $response['body']);
|
|
|
|
|
$this->assertArrayHasKey('smtpSecure', $response['body']);
|
|
|
|
|
|
|
|
|
|
// Cleanup
|
2026-04-20 12:42:52 +00:00
|
|
|
$this->updateSMTP(enabled: false);
|
2026-04-14 14:55:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testUpdateSMTPStatusWithoutAuthentication(): void
|
|
|
|
|
{
|
2026-04-20 12:42:52 +00:00
|
|
|
$response = $this->updateSMTP(enabled: true, authenticated: false);
|
2026-04-14 14:55:39 +00:00
|
|
|
|
|
|
|
|
$this->assertSame(401, $response['headers']['status-code']);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Update SMTP tests
|
|
|
|
|
|
2026-04-16 08:23:31 +00:00
|
|
|
public function testUpdateSMTPCredentials(): void
|
2026-04-14 14:55:39 +00:00
|
|
|
{
|
2026-04-20 12:42:52 +00:00
|
|
|
$response = $this->updateSMTP(
|
2026-04-14 14:55:39 +00:00
|
|
|
senderName: 'Test Sender',
|
|
|
|
|
senderEmail: 'sender@example.com',
|
|
|
|
|
host: 'maildev',
|
|
|
|
|
port: 1025,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->assertSame(200, $response['headers']['status-code']);
|
|
|
|
|
$this->assertNotEmpty($response['body']['$id']);
|
|
|
|
|
$this->assertSame(true, $response['body']['smtpEnabled']);
|
|
|
|
|
$this->assertSame('Test Sender', $response['body']['smtpSenderName']);
|
|
|
|
|
$this->assertSame('sender@example.com', $response['body']['smtpSenderEmail']);
|
|
|
|
|
$this->assertSame('maildev', $response['body']['smtpHost']);
|
|
|
|
|
$this->assertSame(1025, $response['body']['smtpPort']);
|
|
|
|
|
|
|
|
|
|
// Cleanup
|
2026-04-20 12:42:52 +00:00
|
|
|
$this->updateSMTP(enabled: false);
|
2026-04-14 14:55:39 +00:00
|
|
|
}
|
|
|
|
|
|
2026-04-14 15:06:57 +00:00
|
|
|
public function testUpdateSMTPWithOptionalReplyTo(): void
|
2026-04-14 14:55:39 +00:00
|
|
|
{
|
2026-04-20 12:42:52 +00:00
|
|
|
$response = $this->updateSMTP(
|
2026-04-14 14:55:39 +00:00
|
|
|
senderName: 'Full Sender',
|
|
|
|
|
senderEmail: 'sender@example.com',
|
|
|
|
|
host: 'maildev',
|
|
|
|
|
port: 1025,
|
2026-04-20 09:47:06 +00:00
|
|
|
replyToEmail: 'reply@example.com',
|
|
|
|
|
replyToName: 'Full Reply',
|
2026-04-14 14:55:39 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->assertSame(200, $response['headers']['status-code']);
|
|
|
|
|
$this->assertSame(true, $response['body']['smtpEnabled']);
|
|
|
|
|
$this->assertSame('Full Sender', $response['body']['smtpSenderName']);
|
|
|
|
|
$this->assertSame('sender@example.com', $response['body']['smtpSenderEmail']);
|
2026-04-20 09:47:06 +00:00
|
|
|
$this->assertSame('reply@example.com', $response['body']['smtpReplyToEmail']);
|
|
|
|
|
$this->assertSame('Full Reply', $response['body']['smtpReplyToName']);
|
2026-04-14 14:55:39 +00:00
|
|
|
$this->assertSame('maildev', $response['body']['smtpHost']);
|
|
|
|
|
$this->assertSame(1025, $response['body']['smtpPort']);
|
|
|
|
|
|
|
|
|
|
// Cleanup
|
2026-04-20 12:42:52 +00:00
|
|
|
$this->updateSMTP(enabled: false);
|
2026-04-14 14:55:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testUpdateSMTPOverwritesPreviousSettings(): void
|
|
|
|
|
{
|
2026-04-20 12:42:52 +00:00
|
|
|
$this->updateSMTP(
|
2026-04-14 14:55:39 +00:00
|
|
|
senderName: 'First Sender',
|
|
|
|
|
senderEmail: 'first@example.com',
|
|
|
|
|
host: 'maildev',
|
|
|
|
|
port: 1025,
|
|
|
|
|
);
|
|
|
|
|
|
2026-04-20 12:42:52 +00:00
|
|
|
$response = $this->updateSMTP(
|
2026-04-14 14:55:39 +00:00
|
|
|
senderName: 'Second Sender',
|
|
|
|
|
senderEmail: 'second@example.com',
|
|
|
|
|
host: 'maildev',
|
|
|
|
|
port: 1025,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->assertSame(200, $response['headers']['status-code']);
|
|
|
|
|
$this->assertSame('Second Sender', $response['body']['smtpSenderName']);
|
|
|
|
|
$this->assertSame('second@example.com', $response['body']['smtpSenderEmail']);
|
|
|
|
|
|
|
|
|
|
// Cleanup
|
2026-04-20 12:42:52 +00:00
|
|
|
$this->updateSMTP(enabled: false);
|
2026-04-14 14:55:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testUpdateSMTPEnablesSMTP(): void
|
|
|
|
|
{
|
|
|
|
|
// Ensure SMTP is disabled
|
2026-04-20 12:42:52 +00:00
|
|
|
$this->updateSMTP(
|
|
|
|
|
senderName: 'Test Sender',
|
|
|
|
|
senderEmail: 'sender@example.com',
|
|
|
|
|
host: 'maildev',
|
|
|
|
|
port: 1025,
|
|
|
|
|
enabled: false,
|
|
|
|
|
);
|
2026-04-14 14:55:39 +00:00
|
|
|
|
2026-04-20 12:42:52 +00:00
|
|
|
$response = $this->updateSMTP(
|
2026-04-14 14:55:39 +00:00
|
|
|
senderName: 'Test Sender',
|
|
|
|
|
senderEmail: 'sender@example.com',
|
|
|
|
|
host: 'maildev',
|
|
|
|
|
port: 1025,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->assertSame(200, $response['headers']['status-code']);
|
|
|
|
|
$this->assertSame(true, $response['body']['smtpEnabled']);
|
|
|
|
|
|
|
|
|
|
// Cleanup
|
2026-04-20 12:42:52 +00:00
|
|
|
$this->updateSMTP(enabled: false);
|
2026-04-14 14:55:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testUpdateSMTPResponseModel(): void
|
|
|
|
|
{
|
2026-04-20 12:42:52 +00:00
|
|
|
$response = $this->updateSMTP(
|
2026-04-14 14:55:39 +00:00
|
|
|
senderName: 'Test Sender',
|
|
|
|
|
senderEmail: 'sender@example.com',
|
|
|
|
|
host: 'maildev',
|
|
|
|
|
port: 1025,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->assertSame(200, $response['headers']['status-code']);
|
|
|
|
|
$this->assertArrayHasKey('$id', $response['body']);
|
|
|
|
|
$this->assertArrayHasKey('name', $response['body']);
|
|
|
|
|
$this->assertArrayHasKey('smtpEnabled', $response['body']);
|
|
|
|
|
$this->assertArrayHasKey('smtpSenderName', $response['body']);
|
|
|
|
|
$this->assertArrayHasKey('smtpSenderEmail', $response['body']);
|
2026-04-20 09:47:06 +00:00
|
|
|
$this->assertArrayHasKey('smtpReplyToEmail', $response['body']);
|
|
|
|
|
$this->assertArrayHasKey('smtpReplyToName', $response['body']);
|
2026-04-14 14:55:39 +00:00
|
|
|
$this->assertArrayHasKey('smtpHost', $response['body']);
|
|
|
|
|
$this->assertArrayHasKey('smtpPort', $response['body']);
|
|
|
|
|
$this->assertArrayHasKey('smtpUsername', $response['body']);
|
|
|
|
|
$this->assertArrayHasKey('smtpPassword', $response['body']);
|
|
|
|
|
$this->assertArrayHasKey('smtpSecure', $response['body']);
|
|
|
|
|
|
|
|
|
|
// Cleanup
|
2026-04-20 12:42:52 +00:00
|
|
|
$this->updateSMTP(enabled: false);
|
2026-04-14 14:55:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testUpdateSMTPWithoutAuthentication(): void
|
|
|
|
|
{
|
2026-04-20 12:42:52 +00:00
|
|
|
$response = $this->updateSMTP(
|
2026-04-14 14:55:39 +00:00
|
|
|
senderName: 'Test',
|
|
|
|
|
senderEmail: 'sender@example.com',
|
|
|
|
|
host: 'maildev',
|
|
|
|
|
port: 1025,
|
|
|
|
|
authenticated: false,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->assertSame(401, $response['headers']['status-code']);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testUpdateSMTPInvalidSenderEmail(): void
|
|
|
|
|
{
|
2026-04-20 12:42:52 +00:00
|
|
|
$response = $this->updateSMTP(
|
2026-04-14 14:55:39 +00:00
|
|
|
senderName: 'Test',
|
|
|
|
|
senderEmail: 'not-an-email',
|
|
|
|
|
host: 'maildev',
|
|
|
|
|
port: 1025,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->assertSame(400, $response['headers']['status-code']);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testUpdateSMTPEmptySenderName(): void
|
|
|
|
|
{
|
2026-04-20 12:42:52 +00:00
|
|
|
$response = $this->updateSMTP(
|
2026-04-14 14:55:39 +00:00
|
|
|
senderName: '',
|
|
|
|
|
senderEmail: 'sender@example.com',
|
|
|
|
|
host: 'maildev',
|
|
|
|
|
port: 1025,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->assertSame(400, $response['headers']['status-code']);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testUpdateSMTPEmptySenderEmail(): void
|
|
|
|
|
{
|
2026-04-20 12:42:52 +00:00
|
|
|
$response = $this->updateSMTP(
|
2026-04-14 14:55:39 +00:00
|
|
|
senderName: 'Test',
|
|
|
|
|
senderEmail: '',
|
|
|
|
|
host: 'maildev',
|
|
|
|
|
port: 1025,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->assertSame(400, $response['headers']['status-code']);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testUpdateSMTPEmptyHost(): void
|
|
|
|
|
{
|
2026-04-20 12:42:52 +00:00
|
|
|
$response = $this->updateSMTP(
|
2026-04-14 14:55:39 +00:00
|
|
|
senderName: 'Test',
|
|
|
|
|
senderEmail: 'sender@example.com',
|
|
|
|
|
host: '',
|
|
|
|
|
port: 1025,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->assertSame(400, $response['headers']['status-code']);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testUpdateSMTPInvalidHost(): void
|
|
|
|
|
{
|
2026-04-20 12:42:52 +00:00
|
|
|
$response = $this->updateSMTP(
|
2026-04-14 14:55:39 +00:00
|
|
|
senderName: 'Test',
|
|
|
|
|
senderEmail: 'sender@example.com',
|
|
|
|
|
host: 'not a valid host!@#',
|
|
|
|
|
port: 1025,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->assertSame(400, $response['headers']['status-code']);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testUpdateSMTPInvalidReplyToEmail(): void
|
|
|
|
|
{
|
2026-04-20 12:42:52 +00:00
|
|
|
$response = $this->updateSMTP(
|
2026-04-14 14:55:39 +00:00
|
|
|
senderName: 'Test',
|
|
|
|
|
senderEmail: 'sender@example.com',
|
|
|
|
|
host: 'maildev',
|
|
|
|
|
port: 1025,
|
2026-04-20 09:47:06 +00:00
|
|
|
replyToEmail: 'not-an-email',
|
2026-04-14 14:55:39 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->assertSame(400, $response['headers']['status-code']);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testUpdateSMTPInvalidSecure(): void
|
|
|
|
|
{
|
2026-04-20 12:42:52 +00:00
|
|
|
$response = $this->updateSMTP(
|
2026-04-14 14:55:39 +00:00
|
|
|
senderName: 'Test',
|
|
|
|
|
senderEmail: 'sender@example.com',
|
|
|
|
|
host: 'maildev',
|
|
|
|
|
port: 1025,
|
|
|
|
|
secure: 'invalid',
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->assertSame(400, $response['headers']['status-code']);
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-14 15:06:57 +00:00
|
|
|
public function testUpdateSMTPSenderNameMinLength(): void
|
|
|
|
|
{
|
2026-04-20 12:42:52 +00:00
|
|
|
$response = $this->updateSMTP(
|
2026-04-14 15:06:57 +00:00
|
|
|
senderName: 'A',
|
|
|
|
|
senderEmail: 'sender@example.com',
|
|
|
|
|
host: 'maildev',
|
|
|
|
|
port: 1025,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->assertSame(200, $response['headers']['status-code']);
|
|
|
|
|
$this->assertSame('A', $response['body']['smtpSenderName']);
|
|
|
|
|
|
|
|
|
|
// Cleanup
|
2026-04-20 12:42:52 +00:00
|
|
|
$this->updateSMTP(enabled: false);
|
2026-04-14 15:06:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testUpdateSMTPSenderNameMaxLength(): void
|
|
|
|
|
{
|
|
|
|
|
$name = str_repeat('a', 256);
|
2026-04-20 12:42:52 +00:00
|
|
|
$response = $this->updateSMTP(
|
2026-04-14 15:06:57 +00:00
|
|
|
senderName: $name,
|
|
|
|
|
senderEmail: 'sender@example.com',
|
|
|
|
|
host: 'maildev',
|
|
|
|
|
port: 1025,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->assertSame(200, $response['headers']['status-code']);
|
|
|
|
|
$this->assertSame($name, $response['body']['smtpSenderName']);
|
|
|
|
|
|
|
|
|
|
// Cleanup
|
2026-04-20 12:42:52 +00:00
|
|
|
$this->updateSMTP(enabled: false);
|
2026-04-14 15:06:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testUpdateSMTPSenderNameTooLong(): void
|
|
|
|
|
{
|
2026-04-20 12:42:52 +00:00
|
|
|
$response = $this->updateSMTP(
|
2026-04-14 15:06:57 +00:00
|
|
|
senderName: str_repeat('a', 257),
|
|
|
|
|
senderEmail: 'sender@example.com',
|
|
|
|
|
host: 'maildev',
|
|
|
|
|
port: 1025,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->assertSame(400, $response['headers']['status-code']);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testUpdateSMTPUsernameMinLength(): void
|
|
|
|
|
{
|
2026-04-20 12:42:52 +00:00
|
|
|
$response = $this->updateSMTP(
|
2026-04-14 15:06:57 +00:00
|
|
|
senderName: 'Test',
|
|
|
|
|
senderEmail: 'sender@example.com',
|
|
|
|
|
host: 'maildev',
|
|
|
|
|
port: 1025,
|
|
|
|
|
username: 'u',
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->assertSame(200, $response['headers']['status-code']);
|
|
|
|
|
$this->assertSame('u', $response['body']['smtpUsername']);
|
|
|
|
|
|
|
|
|
|
// Cleanup
|
2026-04-20 12:42:52 +00:00
|
|
|
$this->updateSMTP(enabled: false);
|
2026-04-14 15:06:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testUpdateSMTPUsernameMaxLength(): void
|
|
|
|
|
{
|
|
|
|
|
$username = str_repeat('a', 256);
|
2026-04-20 12:42:52 +00:00
|
|
|
$response = $this->updateSMTP(
|
2026-04-14 15:06:57 +00:00
|
|
|
senderName: 'Test',
|
|
|
|
|
senderEmail: 'sender@example.com',
|
|
|
|
|
host: 'maildev',
|
|
|
|
|
port: 1025,
|
|
|
|
|
username: $username,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->assertSame(200, $response['headers']['status-code']);
|
|
|
|
|
$this->assertSame($username, $response['body']['smtpUsername']);
|
|
|
|
|
|
|
|
|
|
// Cleanup
|
2026-04-20 12:42:52 +00:00
|
|
|
$this->updateSMTP(enabled: false);
|
2026-04-14 15:06:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testUpdateSMTPUsernameTooLong(): void
|
|
|
|
|
{
|
2026-04-20 12:42:52 +00:00
|
|
|
$response = $this->updateSMTP(
|
2026-04-14 15:06:57 +00:00
|
|
|
senderName: 'Test',
|
|
|
|
|
senderEmail: 'sender@example.com',
|
|
|
|
|
host: 'maildev',
|
|
|
|
|
port: 1025,
|
|
|
|
|
username: str_repeat('a', 257),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->assertSame(400, $response['headers']['status-code']);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testUpdateSMTPUsernameEmpty(): void
|
|
|
|
|
{
|
2026-04-20 12:42:52 +00:00
|
|
|
$response = $this->updateSMTP(
|
2026-04-14 15:06:57 +00:00
|
|
|
senderName: 'Test',
|
|
|
|
|
senderEmail: 'sender@example.com',
|
|
|
|
|
host: 'maildev',
|
|
|
|
|
port: 1025,
|
|
|
|
|
username: '',
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->assertSame(400, $response['headers']['status-code']);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testUpdateSMTPPasswordMinLength(): void
|
|
|
|
|
{
|
2026-04-20 12:42:52 +00:00
|
|
|
$response = $this->updateSMTP(
|
2026-04-14 15:06:57 +00:00
|
|
|
senderName: 'Test',
|
|
|
|
|
senderEmail: 'sender@example.com',
|
|
|
|
|
host: 'maildev',
|
|
|
|
|
port: 1025,
|
|
|
|
|
password: 'p',
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->assertSame(200, $response['headers']['status-code']);
|
|
|
|
|
$this->assertSame('p', $response['body']['smtpPassword']);
|
|
|
|
|
|
|
|
|
|
// Cleanup
|
2026-04-20 12:42:52 +00:00
|
|
|
$this->updateSMTP(enabled: false);
|
2026-04-14 15:06:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testUpdateSMTPPasswordMaxLength(): void
|
|
|
|
|
{
|
|
|
|
|
$password = str_repeat('a', 256);
|
2026-04-20 12:42:52 +00:00
|
|
|
$response = $this->updateSMTP(
|
2026-04-14 15:06:57 +00:00
|
|
|
senderName: 'Test',
|
|
|
|
|
senderEmail: 'sender@example.com',
|
|
|
|
|
host: 'maildev',
|
|
|
|
|
port: 1025,
|
|
|
|
|
password: $password,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->assertSame(200, $response['headers']['status-code']);
|
|
|
|
|
$this->assertSame($password, $response['body']['smtpPassword']);
|
|
|
|
|
|
|
|
|
|
// Cleanup
|
2026-04-20 12:42:52 +00:00
|
|
|
$this->updateSMTP(enabled: false);
|
2026-04-14 15:06:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testUpdateSMTPPasswordTooLong(): void
|
|
|
|
|
{
|
2026-04-20 12:42:52 +00:00
|
|
|
$response = $this->updateSMTP(
|
2026-04-14 15:06:57 +00:00
|
|
|
senderName: 'Test',
|
|
|
|
|
senderEmail: 'sender@example.com',
|
|
|
|
|
host: 'maildev',
|
|
|
|
|
port: 1025,
|
|
|
|
|
password: str_repeat('a', 257),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->assertSame(400, $response['headers']['status-code']);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testUpdateSMTPPasswordEmpty(): void
|
|
|
|
|
{
|
2026-04-20 12:42:52 +00:00
|
|
|
$response = $this->updateSMTP(
|
2026-04-14 15:06:57 +00:00
|
|
|
senderName: 'Test',
|
|
|
|
|
senderEmail: 'sender@example.com',
|
|
|
|
|
host: 'maildev',
|
|
|
|
|
port: 1025,
|
|
|
|
|
password: '',
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->assertSame(400, $response['headers']['status-code']);
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-14 15:01:56 +00:00
|
|
|
public function testUpdateSMTPWithoutSecure(): void
|
2026-04-14 14:55:39 +00:00
|
|
|
{
|
2026-04-20 12:42:52 +00:00
|
|
|
$response = $this->updateSMTP(
|
2026-04-14 14:55:39 +00:00
|
|
|
senderName: 'Test Sender',
|
|
|
|
|
senderEmail: 'sender@example.com',
|
|
|
|
|
host: 'maildev',
|
|
|
|
|
port: 1025,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->assertSame(200, $response['headers']['status-code']);
|
|
|
|
|
$this->assertSame('', $response['body']['smtpSecure']);
|
|
|
|
|
|
|
|
|
|
// Cleanup
|
2026-04-20 12:42:52 +00:00
|
|
|
$this->updateSMTP(enabled: false);
|
2026-04-14 14:55:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testUpdateSMTPInvalidConnectionRefused(): void
|
|
|
|
|
{
|
2026-04-20 12:42:52 +00:00
|
|
|
$response = $this->updateSMTP(
|
2026-04-14 14:55:39 +00:00
|
|
|
senderName: 'Test',
|
|
|
|
|
senderEmail: 'sender@example.com',
|
|
|
|
|
host: 'localhost',
|
|
|
|
|
port: 12345,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->assertSame(400, $response['headers']['status-code']);
|
|
|
|
|
$this->assertSame('project_smtp_config_invalid', $response['body']['type']);
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-20 13:36:49 +00:00
|
|
|
public function testUpdateSMTPLegacyReplyToAndResponseFormat(): void
|
|
|
|
|
{
|
|
|
|
|
$headers = \array_merge([
|
|
|
|
|
'content-type' => 'application/json',
|
|
|
|
|
'x-appwrite-project' => $this->getProject()['$id'],
|
|
|
|
|
'x-appwrite-response-format' => '1.9.1',
|
|
|
|
|
], $this->getHeaders());
|
|
|
|
|
|
|
|
|
|
// Legacy client sends `replyTo` (not `replyToEmail`). Request filter maps it.
|
|
|
|
|
$response = $this->client->call(
|
|
|
|
|
Client::METHOD_PATCH,
|
|
|
|
|
'/project/smtp',
|
|
|
|
|
$headers,
|
|
|
|
|
[
|
|
|
|
|
'enabled' => true,
|
|
|
|
|
'senderName' => 'Legacy Sender',
|
|
|
|
|
'senderEmail' => 'legacy-sender@example.com',
|
|
|
|
|
'host' => 'maildev',
|
|
|
|
|
'port' => 1025,
|
|
|
|
|
'replyTo' => 'legacy-reply@example.com',
|
|
|
|
|
],
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->assertSame(200, $response['headers']['status-code']);
|
|
|
|
|
$this->assertSame(true, $response['body']['smtpEnabled']);
|
|
|
|
|
$this->assertSame('Legacy Sender', $response['body']['smtpSenderName']);
|
|
|
|
|
$this->assertSame('legacy-sender@example.com', $response['body']['smtpSenderEmail']);
|
|
|
|
|
|
|
|
|
|
// Response filter must expose smtpReplyTo and strip smtpReplyToEmail / smtpReplyToName.
|
|
|
|
|
$this->assertArrayHasKey('smtpReplyTo', $response['body']);
|
|
|
|
|
$this->assertArrayNotHasKey('smtpReplyToEmail', $response['body']);
|
|
|
|
|
$this->assertArrayNotHasKey('smtpReplyToName', $response['body']);
|
|
|
|
|
$this->assertSame('legacy-reply@example.com', $response['body']['smtpReplyTo']);
|
|
|
|
|
|
|
|
|
|
// Sanity-check: a modern (non-legacy) read sees the new field names.
|
|
|
|
|
$modern = $this->updateSMTP(enabled: true);
|
|
|
|
|
$this->assertArrayHasKey('smtpReplyToEmail', $modern['body']);
|
|
|
|
|
$this->assertSame('legacy-reply@example.com', $modern['body']['smtpReplyToEmail']);
|
|
|
|
|
|
|
|
|
|
// Cleanup
|
|
|
|
|
$this->updateSMTP(enabled: false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testCreateSMTPTestLegacyInlineParams(): void
|
|
|
|
|
{
|
|
|
|
|
// Seed the project with a distinct SMTP config so we can prove the
|
|
|
|
|
// inline (1.9.1-style) params take precedence over project config.
|
|
|
|
|
$this->updateSMTP(
|
|
|
|
|
senderName: 'Project Sender',
|
|
|
|
|
senderEmail: 'project-sender@example.com',
|
|
|
|
|
host: 'maildev',
|
|
|
|
|
port: 1025,
|
|
|
|
|
replyToEmail: 'project-reply@example.com',
|
|
|
|
|
replyToName: 'Project Reply',
|
|
|
|
|
enabled: false,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$recipient = 'legacy-smtp-' . \uniqid() . '@appwrite.io';
|
|
|
|
|
|
|
|
|
|
$headers = \array_merge([
|
|
|
|
|
'content-type' => 'application/json',
|
|
|
|
|
'x-appwrite-project' => $this->getProject()['$id'],
|
|
|
|
|
'x-appwrite-response-format' => '1.9.1',
|
|
|
|
|
], $this->getHeaders());
|
|
|
|
|
|
|
|
|
|
$response = $this->client->call(
|
|
|
|
|
Client::METHOD_POST,
|
|
|
|
|
'/project/smtp/tests',
|
|
|
|
|
$headers,
|
|
|
|
|
[
|
|
|
|
|
'emails' => [$recipient],
|
|
|
|
|
'senderName' => 'Inline Legacy Sender',
|
|
|
|
|
'senderEmail' => 'inline-legacy@appwrite.io',
|
|
|
|
|
'replyTo' => 'inline-legacy-reply@appwrite.io',
|
|
|
|
|
'host' => 'maildev',
|
|
|
|
|
'port' => 1025,
|
|
|
|
|
'username' => 'user',
|
|
|
|
|
'password' => 'password',
|
|
|
|
|
],
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->assertSame(204, $response['headers']['status-code']);
|
|
|
|
|
$this->assertEmpty($response['body']);
|
|
|
|
|
|
|
|
|
|
// Verify the email was sent using the inline params (not project SMTP).
|
|
|
|
|
$email = $this->getLastEmailByAddress($recipient, function ($email) {
|
|
|
|
|
$this->assertSame('Custom SMTP email sample', $email['subject']);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
$this->assertSame('inline-legacy@appwrite.io', $email['from'][0]['address']);
|
|
|
|
|
$this->assertSame('Inline Legacy Sender', $email['from'][0]['name']);
|
|
|
|
|
$this->assertSame('inline-legacy-reply@appwrite.io', $email['replyTo'][0]['address']);
|
|
|
|
|
$this->assertSame('Inline Legacy Sender', $email['replyTo'][0]['name']);
|
|
|
|
|
|
|
|
|
|
// Cleanup
|
|
|
|
|
$this->updateSMTP(enabled: false);
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-14 14:55:39 +00:00
|
|
|
public function testUpdateSMTPBackwardsCompatibilityDisable(): void
|
|
|
|
|
{
|
|
|
|
|
// First enable SMTP
|
2026-04-20 12:42:52 +00:00
|
|
|
$this->updateSMTP(
|
|
|
|
|
senderName: 'Test',
|
|
|
|
|
senderEmail: 'sender@example.com',
|
|
|
|
|
host: 'maildev',
|
|
|
|
|
port: 1025,
|
|
|
|
|
enabled: true,
|
|
|
|
|
);
|
2026-04-14 14:55:39 +00:00
|
|
|
|
|
|
|
|
// Use the deprecated enabled=false parameter to disable
|
2026-04-20 12:42:52 +00:00
|
|
|
$response = $this->updateSMTP(
|
2026-04-14 14:55:39 +00:00
|
|
|
senderName: 'Test',
|
|
|
|
|
senderEmail: 'sender@example.com',
|
|
|
|
|
host: 'maildev',
|
|
|
|
|
port: 1025,
|
|
|
|
|
enabled: false,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->assertSame(200, $response['headers']['status-code']);
|
|
|
|
|
$this->assertSame(false, $response['body']['smtpEnabled']);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create SMTP test tests
|
|
|
|
|
|
|
|
|
|
public function testCreateSMTPTest(): void
|
|
|
|
|
{
|
|
|
|
|
// First configure SMTP
|
2026-04-20 12:42:52 +00:00
|
|
|
$this->updateSMTP(
|
2026-04-14 14:55:39 +00:00
|
|
|
senderName: 'Test Sender',
|
|
|
|
|
senderEmail: 'sender@example.com',
|
|
|
|
|
host: 'maildev',
|
|
|
|
|
port: 1025,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$response = $this->createSMTPTest(['recipient@example.com']);
|
|
|
|
|
|
|
|
|
|
$this->assertSame(204, $response['headers']['status-code']);
|
|
|
|
|
$this->assertEmpty($response['body']);
|
|
|
|
|
|
|
|
|
|
// Cleanup
|
2026-04-20 12:42:52 +00:00
|
|
|
$this->updateSMTP(enabled: false);
|
2026-04-14 14:55:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testCreateSMTPTestMultipleRecipients(): void
|
|
|
|
|
{
|
|
|
|
|
// First configure SMTP
|
2026-04-20 12:42:52 +00:00
|
|
|
$this->updateSMTP(
|
2026-04-14 14:55:39 +00:00
|
|
|
senderName: 'Test Sender',
|
|
|
|
|
senderEmail: 'sender@example.com',
|
|
|
|
|
host: 'maildev',
|
|
|
|
|
port: 1025,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$response = $this->createSMTPTest([
|
|
|
|
|
'recipient1@example.com',
|
|
|
|
|
'recipient2@example.com',
|
|
|
|
|
'recipient3@example.com',
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$this->assertSame(204, $response['headers']['status-code']);
|
|
|
|
|
$this->assertEmpty($response['body']);
|
|
|
|
|
|
|
|
|
|
// Cleanup
|
2026-04-20 12:42:52 +00:00
|
|
|
$this->updateSMTP(enabled: false);
|
2026-04-14 14:55:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testCreateSMTPTestWhenSMTPDisabled(): void
|
|
|
|
|
{
|
|
|
|
|
// Ensure SMTP is disabled
|
2026-04-20 12:42:52 +00:00
|
|
|
$this->updateSMTP(
|
|
|
|
|
senderName: 'Test Sender',
|
|
|
|
|
senderEmail: 'sender@example.com',
|
|
|
|
|
host: 'maildev',
|
|
|
|
|
port: 1025,
|
|
|
|
|
enabled: false,
|
|
|
|
|
);
|
2026-04-14 14:55:39 +00:00
|
|
|
|
|
|
|
|
$response = $this->createSMTPTest(['recipient@example.com']);
|
|
|
|
|
|
|
|
|
|
$this->assertSame(400, $response['headers']['status-code']);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testCreateSMTPTestWithoutAuthentication(): void
|
|
|
|
|
{
|
|
|
|
|
$response = $this->createSMTPTest(['recipient@example.com'], false);
|
|
|
|
|
|
|
|
|
|
$this->assertSame(401, $response['headers']['status-code']);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testCreateSMTPTestEmptyEmails(): void
|
|
|
|
|
{
|
|
|
|
|
// First configure SMTP
|
2026-04-20 12:42:52 +00:00
|
|
|
$this->updateSMTP(
|
2026-04-14 14:55:39 +00:00
|
|
|
senderName: 'Test Sender',
|
|
|
|
|
senderEmail: 'sender@example.com',
|
|
|
|
|
host: 'maildev',
|
|
|
|
|
port: 1025,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$response = $this->createSMTPTest([]);
|
|
|
|
|
|
2026-04-14 15:06:57 +00:00
|
|
|
$this->assertSame(204, $response['headers']['status-code']);
|
|
|
|
|
$this->assertEmpty($response['body']);
|
2026-04-14 14:55:39 +00:00
|
|
|
|
|
|
|
|
// Cleanup
|
2026-04-20 12:42:52 +00:00
|
|
|
$this->updateSMTP(enabled: false);
|
2026-04-14 14:55:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testCreateSMTPTestInvalidEmail(): void
|
|
|
|
|
{
|
|
|
|
|
// First configure SMTP
|
2026-04-20 12:42:52 +00:00
|
|
|
$this->updateSMTP(
|
2026-04-14 14:55:39 +00:00
|
|
|
senderName: 'Test Sender',
|
|
|
|
|
senderEmail: 'sender@example.com',
|
|
|
|
|
host: 'maildev',
|
|
|
|
|
port: 1025,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$response = $this->createSMTPTest(['not-an-email']);
|
|
|
|
|
|
|
|
|
|
$this->assertSame(400, $response['headers']['status-code']);
|
|
|
|
|
|
|
|
|
|
// Cleanup
|
2026-04-20 12:42:52 +00:00
|
|
|
$this->updateSMTP(enabled: false);
|
2026-04-14 14:55:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testCreateSMTPTestExceedsMaxEmails(): void
|
|
|
|
|
{
|
|
|
|
|
// First configure SMTP
|
2026-04-20 12:42:52 +00:00
|
|
|
$this->updateSMTP(
|
2026-04-14 14:55:39 +00:00
|
|
|
senderName: 'Test Sender',
|
|
|
|
|
senderEmail: 'sender@example.com',
|
|
|
|
|
host: 'maildev',
|
|
|
|
|
port: 1025,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$emails = [];
|
|
|
|
|
for ($i = 1; $i <= 11; $i++) {
|
|
|
|
|
$emails[] = "recipient{$i}@example.com";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$response = $this->createSMTPTest($emails);
|
|
|
|
|
|
|
|
|
|
$this->assertSame(400, $response['headers']['status-code']);
|
|
|
|
|
|
|
|
|
|
// Cleanup
|
2026-04-20 12:42:52 +00:00
|
|
|
$this->updateSMTP(enabled: false);
|
2026-04-14 14:55:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testCreateSMTPTestMaxEmails(): void
|
|
|
|
|
{
|
|
|
|
|
// First configure SMTP
|
2026-04-20 12:42:52 +00:00
|
|
|
$this->updateSMTP(
|
2026-04-14 14:55:39 +00:00
|
|
|
senderName: 'Test Sender',
|
|
|
|
|
senderEmail: 'sender@example.com',
|
|
|
|
|
host: 'maildev',
|
|
|
|
|
port: 1025,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$emails = [];
|
|
|
|
|
for ($i = 1; $i <= 10; $i++) {
|
|
|
|
|
$emails[] = "recipient{$i}@example.com";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$response = $this->createSMTPTest($emails);
|
|
|
|
|
|
|
|
|
|
$this->assertSame(204, $response['headers']['status-code']);
|
|
|
|
|
$this->assertEmpty($response['body']);
|
|
|
|
|
|
|
|
|
|
// Cleanup
|
2026-04-20 12:42:52 +00:00
|
|
|
$this->updateSMTP(enabled: false);
|
2026-04-14 14:55:39 +00:00
|
|
|
}
|
|
|
|
|
|
2026-04-14 15:09:37 +00:00
|
|
|
// Integration tests
|
|
|
|
|
|
|
|
|
|
public function testCreateSMTPTestEmailDelivery(): void
|
|
|
|
|
{
|
|
|
|
|
$senderName = 'SMTP Test Sender';
|
|
|
|
|
$senderEmail = 'smtptest@appwrite.io';
|
|
|
|
|
$replyToEmail = 'smtpreply@appwrite.io';
|
2026-04-20 09:47:06 +00:00
|
|
|
$replyToName = 'SMTP Reply Team';
|
2026-04-14 15:09:37 +00:00
|
|
|
$recipientEmail = 'smtpdelivery-' . \uniqid() . '@appwrite.io';
|
|
|
|
|
|
2026-04-20 09:47:06 +00:00
|
|
|
// Configure SMTP with reply-to and auth credentials
|
2026-04-20 12:42:52 +00:00
|
|
|
$response = $this->updateSMTP(
|
2026-04-14 15:09:37 +00:00
|
|
|
senderName: $senderName,
|
|
|
|
|
senderEmail: $senderEmail,
|
|
|
|
|
host: 'maildev',
|
|
|
|
|
port: 1025,
|
2026-04-20 09:47:06 +00:00
|
|
|
replyToEmail: $replyToEmail,
|
|
|
|
|
replyToName: $replyToName,
|
2026-04-14 15:20:03 +00:00
|
|
|
username: 'user',
|
|
|
|
|
password: 'password',
|
2026-04-14 15:09:37 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->assertSame(200, $response['headers']['status-code']);
|
|
|
|
|
$this->assertSame(true, $response['body']['smtpEnabled']);
|
|
|
|
|
|
|
|
|
|
// Trigger test email
|
|
|
|
|
$response = $this->createSMTPTest([$recipientEmail]);
|
|
|
|
|
|
|
|
|
|
$this->assertSame(204, $response['headers']['status-code']);
|
|
|
|
|
|
|
|
|
|
// Verify email arrived via maildev
|
|
|
|
|
$email = $this->getLastEmailByAddress($recipientEmail, function ($email) {
|
|
|
|
|
$this->assertSame('Custom SMTP email sample', $email['subject']);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
$this->assertSame($senderEmail, $email['from'][0]['address']);
|
|
|
|
|
$this->assertSame($senderName, $email['from'][0]['name']);
|
|
|
|
|
$this->assertSame($replyToEmail, $email['replyTo'][0]['address']);
|
2026-04-20 09:47:06 +00:00
|
|
|
$this->assertSame($replyToName, $email['replyTo'][0]['name']);
|
2026-04-14 15:09:37 +00:00
|
|
|
$this->assertSame('Custom SMTP email sample', $email['subject']);
|
|
|
|
|
$this->assertStringContainsStringIgnoringCase('working correctly', $email['text']);
|
|
|
|
|
$this->assertStringContainsStringIgnoringCase('working correctly', $email['html']);
|
|
|
|
|
|
|
|
|
|
// Cleanup
|
2026-04-20 12:42:52 +00:00
|
|
|
$this->updateSMTP(enabled: false);
|
2026-04-14 15:09:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testMagicURLLoginUsesCustomSMTP(): void
|
|
|
|
|
{
|
|
|
|
|
$senderName = 'Custom Auth Mailer';
|
|
|
|
|
$senderEmail = 'authmailer@appwrite.io';
|
|
|
|
|
$recipientEmail = 'magicurl-' . \uniqid() . '@appwrite.io';
|
|
|
|
|
|
2026-04-14 15:20:03 +00:00
|
|
|
// Configure custom SMTP with auth credentials
|
2026-04-20 12:42:52 +00:00
|
|
|
$response = $this->updateSMTP(
|
2026-04-14 15:09:37 +00:00
|
|
|
senderName: $senderName,
|
|
|
|
|
senderEmail: $senderEmail,
|
2026-04-14 15:20:22 +00:00
|
|
|
host: 'maildev',
|
|
|
|
|
port: 1025,
|
|
|
|
|
username: 'user',
|
|
|
|
|
password: 'password',
|
2026-04-14 15:09:37 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->assertSame(200, $response['headers']['status-code']);
|
|
|
|
|
$this->assertSame(true, $response['body']['smtpEnabled']);
|
|
|
|
|
|
|
|
|
|
// Trigger MagicURL login as a client (no auth headers needed)
|
|
|
|
|
$response = $this->client->call(Client::METHOD_POST, '/account/tokens/magic-url', [
|
|
|
|
|
'origin' => 'http://localhost',
|
|
|
|
|
'content-type' => 'application/json',
|
|
|
|
|
'x-appwrite-project' => $this->getProject()['$id'],
|
|
|
|
|
], [
|
|
|
|
|
'userId' => ID::unique(),
|
|
|
|
|
'email' => $recipientEmail,
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$this->assertSame(201, $response['headers']['status-code']);
|
|
|
|
|
|
|
|
|
|
// Verify the email arrived with custom SMTP sender details
|
|
|
|
|
$email = $this->getLastEmailByAddress($recipientEmail, function ($email) {
|
|
|
|
|
$this->assertStringContainsString('Login', $email['subject']);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
$this->assertSame($senderEmail, $email['from'][0]['address']);
|
|
|
|
|
$this->assertSame($senderName, $email['from'][0]['name']);
|
|
|
|
|
$this->assertSame($this->getProject()['name'] . ' Login', $email['subject']);
|
|
|
|
|
|
|
|
|
|
// Cleanup
|
2026-04-20 12:42:52 +00:00
|
|
|
$this->updateSMTP(enabled: false);
|
2026-04-14 15:09:37 +00:00
|
|
|
}
|
|
|
|
|
|
2026-04-14 14:55:39 +00:00
|
|
|
// Helpers
|
|
|
|
|
|
2026-04-20 12:42:52 +00:00
|
|
|
protected function updateSMTP(
|
|
|
|
|
?string $senderName = null,
|
|
|
|
|
?string $senderEmail = null,
|
|
|
|
|
?string $host = null,
|
|
|
|
|
?int $port = null,
|
2026-04-20 09:47:06 +00:00
|
|
|
?string $replyToEmail = null,
|
|
|
|
|
?string $replyToName = null,
|
2026-04-14 15:01:56 +00:00
|
|
|
?string $username = null,
|
|
|
|
|
?string $password = null,
|
|
|
|
|
?string $secure = null,
|
2026-04-14 14:55:39 +00:00
|
|
|
?bool $enabled = null,
|
|
|
|
|
bool $authenticated = true,
|
|
|
|
|
): mixed {
|
|
|
|
|
$headers = [
|
|
|
|
|
'content-type' => 'application/json',
|
|
|
|
|
'x-appwrite-project' => $this->getProject()['$id'],
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
if ($authenticated) {
|
|
|
|
|
$headers = array_merge($headers, $this->getHeaders());
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-20 12:42:52 +00:00
|
|
|
$params = [];
|
2026-04-14 15:01:56 +00:00
|
|
|
|
2026-04-20 12:42:52 +00:00
|
|
|
foreach (['senderName', 'senderEmail', 'host', 'port', 'replyToEmail', 'replyToName', 'username', 'password', 'secure', 'enabled'] as $key) {
|
|
|
|
|
if (!\is_null(${$key})) {
|
|
|
|
|
$params[$key] = ${$key};
|
|
|
|
|
}
|
2026-04-14 14:55:39 +00:00
|
|
|
}
|
|
|
|
|
|
2026-04-20 12:42:52 +00:00
|
|
|
return $this->client->call(Client::METHOD_PATCH, '/project/smtp', $headers, $params);
|
2026-04-14 14:55:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param array<string> $emails
|
|
|
|
|
*/
|
|
|
|
|
protected function createSMTPTest(array $emails, bool $authenticated = true): mixed
|
|
|
|
|
{
|
|
|
|
|
$headers = [
|
|
|
|
|
'content-type' => 'application/json',
|
|
|
|
|
'x-appwrite-project' => $this->getProject()['$id'],
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
if ($authenticated) {
|
|
|
|
|
$headers = array_merge($headers, $this->getHeaders());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $this->client->call(Client::METHOD_POST, '/project/smtp/tests', $headers, [
|
|
|
|
|
'emails' => $emails,
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
}
|