diff --git a/app/init/registers.php b/app/init/registers.php index 7c2f822fdd..4fac60b877 100644 --- a/app/init/registers.php +++ b/app/init/registers.php @@ -6,7 +6,6 @@ use Appwrite\Hooks\Hooks; use Appwrite\PubSub\Adapter\Redis as PubSub; use Appwrite\URL\URL as AppwriteURL; use MaxMind\Db\Reader; -use PHPMailer\PHPMailer\PHPMailer; use Swoole\Database\PDOProxy; use Utopia\Cache\Adapter\Redis as RedisCache; use Utopia\Config\Config; @@ -25,6 +24,7 @@ use Utopia\Logger\Adapter\LogOwl; use Utopia\Logger\Adapter\Raygun; use Utopia\Logger\Adapter\Sentry; use Utopia\Logger\Logger; +use Utopia\Messaging\Adapter\Email\SMTP; use Utopia\Mongo\Client as MongoClient; use Utopia\Pools\Adapter\Stack as StackPool; use Utopia\Pools\Adapter\Swoole as SwoolePool; @@ -433,35 +433,21 @@ $register->set('db', function () { }); $register->set('smtp', function () { - $mail = new PHPMailer(true); + $username = System::getEnv('_APP_SMTP_USERNAME', ''); + $password = System::getEnv('_APP_SMTP_PASSWORD', ''); - $mail->isSMTP(); - - $username = System::getEnv('_APP_SMTP_USERNAME'); - $password = System::getEnv('_APP_SMTP_PASSWORD'); - - $mail->XMailer = 'Appwrite Mailer'; - $mail->Host = System::getEnv('_APP_SMTP_HOST', 'smtp'); - $mail->Port = System::getEnv('_APP_SMTP_PORT', 25); - $mail->SMTPAuth = !empty($username) && !empty($password); - $mail->Username = $username; - $mail->Password = $password; - $mail->SMTPSecure = System::getEnv('_APP_SMTP_SECURE', ''); - $mail->SMTPAutoTLS = false; - $mail->SMTPKeepAlive = true; - $mail->CharSet = 'UTF-8'; - $mail->Timeout = 10; /* Connection timeout */ - $mail->getSMTPInstance()->Timelimit = 30; /* Timeout for each individual SMTP command (e.g. HELO, EHLO, etc.) */ - - $from = \urldecode(System::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME . ' Server')); - $email = System::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', APP_EMAIL_TEAM); - - $mail->setFrom($email, $from); - $mail->addReplyTo($email, $from); - - $mail->isHTML(true); - - return $mail; + return new SMTP( + host: System::getEnv('_APP_SMTP_HOST', 'smtp'), + port: (int) System::getEnv('_APP_SMTP_PORT', 25), + username: $username, + password: $password, + smtpSecure: System::getEnv('_APP_SMTP_SECURE', ''), + smtpAutoTLS: false, + xMailer: 'Appwrite Mailer', + timeout: 10, + keepAlive: true, + timelimit: 30, + ); }); $register->set('geodb', function () { return new Reader(__DIR__ . '/../assets/dbip/dbip-country-lite-2025-12.mmdb'); diff --git a/composer.json b/composer.json index 1a530bfc5b..3d7e1b0e55 100644 --- a/composer.json +++ b/composer.json @@ -72,7 +72,7 @@ "utopia-php/image": "0.8.*", "utopia-php/locale": "0.8.*", "utopia-php/logger": "0.6.*", - "utopia-php/messaging": "0.20.*", + "utopia-php/messaging": "dev-feat-smtp-enhancements", "utopia-php/migration": "1.9.*", "utopia-php/platform": "0.7.*", "utopia-php/pools": "1.*", diff --git a/composer.lock b/composer.lock index 0a79c5bee3..5d92374109 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "b5261855586680e467168f527e0634ae", + "content-hash": "505d09ff5da7c5199622679ae9e11bc6", "packages": [ { "name": "adhocore/jwt", @@ -4467,16 +4467,16 @@ }, { "name": "utopia-php/messaging", - "version": "0.20.1", + "version": "dev-feat-smtp-enhancements", "source": { "type": "git", "url": "https://github.com/utopia-php/messaging.git", - "reference": "fcb4c3c46a48008a677957690bd45ec934dd33b0" + "reference": "6988c227c08095ad88aad030bf3648f4ea6c88f0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/messaging/zipball/fcb4c3c46a48008a677957690bd45ec934dd33b0", - "reference": "fcb4c3c46a48008a677957690bd45ec934dd33b0", + "url": "https://api.github.com/repos/utopia-php/messaging/zipball/6988c227c08095ad88aad030bf3648f4ea6c88f0", + "reference": "6988c227c08095ad88aad030bf3648f4ea6c88f0", "shasum": "" }, "require": { @@ -4512,9 +4512,9 @@ ], "support": { "issues": "https://github.com/utopia-php/messaging/issues", - "source": "https://github.com/utopia-php/messaging/tree/0.20.1" + "source": "https://github.com/utopia-php/messaging/tree/feat-smtp-enhancements" }, - "time": "2026-02-06T09:56:06+00:00" + "time": "2026-04-01T10:41:57+00:00" }, { "name": "utopia-php/migration", @@ -8435,7 +8435,9 @@ ], "aliases": [], "minimum-stability": "dev", - "stability-flags": {}, + "stability-flags": { + "utopia-php/messaging": 20 + }, "prefer-stable": true, "prefer-lowest": false, "platform": { diff --git a/src/Appwrite/Platform/Tasks/Doctor.php b/src/Appwrite/Platform/Tasks/Doctor.php index 9a9c2fdf73..aa916a559c 100644 --- a/src/Appwrite/Platform/Tasks/Doctor.php +++ b/src/Appwrite/Platform/Tasks/Doctor.php @@ -4,7 +4,6 @@ namespace Appwrite\Platform\Tasks; use Appwrite\ClamAV\Network; use Appwrite\PubSub\Adapter\Pool as PubSubPool; -use PHPMailer\PHPMailer\PHPMailer; use Utopia\Cache\Adapter\Pool as CachePool; use Utopia\Config\Config; use Utopia\Console; @@ -13,6 +12,8 @@ use Utopia\Domains\Domain; use Utopia\DSN\DSN; use Utopia\Http\Http; use Utopia\Logger\Logger; +use Utopia\Messaging\Adapter\Email as EmailAdapter; +use Utopia\Messaging\Messages\Email as EmailMessage; use Utopia\Platform\Action; use Utopia\Pools\Group; use Utopia\Queue\Broker\Pool as BrokerPool; @@ -212,15 +213,18 @@ class Doctor extends Action } try { - /* @var PHPMailer $mail */ - $mail = $register->get('smtp'); + /** @var EmailAdapter $smtp */ + $smtp = $register->get('smtp'); - $mail->addAddress('demo@example.com', 'Example.com'); - $mail->Subject = 'Test SMTP Connection'; - $mail->Body = 'Hello World'; - $mail->AltBody = 'Hello World'; + $emailMessage = new EmailMessage( + to: ['demo@example.com'], + subject: 'Test SMTP Connection', + content: 'Hello World', + fromName: \urldecode(System::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME . ' Server')), + fromEmail: System::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', APP_EMAIL_TEAM), + ); - $mail->send(); + $smtp->send($emailMessage); Console::success('🟢 ' . str_pad("SMTP", 50, '.') . 'connected'); } catch (\Throwable) { Console::error('🔴 ' . str_pad("SMTP", 47, '.') . 'disconnected'); diff --git a/src/Appwrite/Platform/Workers/Mails.php b/src/Appwrite/Platform/Workers/Mails.php index f144c58e1b..83ddb082ab 100644 --- a/src/Appwrite/Platform/Workers/Mails.php +++ b/src/Appwrite/Platform/Workers/Mails.php @@ -4,10 +4,13 @@ namespace Appwrite\Platform\Workers; use Appwrite\Template\Template; use Exception; -use PHPMailer\PHPMailer\PHPMailer; use Swoole\Runtime; use Utopia\Database\Document; use Utopia\Logger\Log; +use Utopia\Messaging\Adapter\Email as EmailAdapter; +use Utopia\Messaging\Adapter\Email\SMTP; +use Utopia\Messaging\Messages\Email as EmailMessage; +use Utopia\Messaging\Messages\Email\Attachment; use Utopia\Platform\Action; use Utopia\Queue\Message; use Utopia\Registry\Registry; @@ -49,9 +52,9 @@ class Mails extends Action /** * @param Message $message + * @param Document $project * @param Registry $register * @param Log $log - * @throws \PHPMailer\PHPMailer\Exception * @return void * @throws Exception */ @@ -132,58 +135,77 @@ class Mails extends Action // render() will return the subject in
tags, so use strip_tags() to remove them $subject = \strip_tags($subjectTemplate->render()); - /** @var PHPMailer $mail */ - $mail = empty($smtp) + /** @var EmailAdapter $adapter */ + $adapter = empty($smtp) ? $register->get('smtp') - : $this->getMailer($smtp); + : new SMTP( + host: $smtp['host'], + port: (int) $smtp['port'], + username: $smtp['username'] ?? '', + password: $smtp['password'] ?? '', + smtpSecure: $smtp['secure'] ?? '', + smtpAutoTLS: false, + xMailer: 'Appwrite Mailer', + timeout: 10, + keepAlive: true, + timelimit: 30, + ); - $mail->clearAddresses(); - $mail->clearAllRecipients(); - $mail->clearReplyTos(); - $mail->clearAttachments(); - $mail->clearBCCs(); - $mail->clearCCs(); - $mail->addAddress($recipient, $name); - $mail->Subject = $subject; - $mail->Body = $body; + // Resolve from/replyTo using fallback hierarchy: Custom options > SMTP config > Defaults + $defaultFromEmail = System::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', APP_EMAIL_TEAM); + $defaultFromName = \urldecode(System::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME . ' Server')); - $mail->AltBody = $body; - $mail->AltBody = preg_replace('/