Merge pull request #6052 from appwrite/fix-smtp-behaviour
Fix: SMTP behaviour
This commit is contained in:
commit
98d20dcd4d
14 changed files with 308 additions and 205 deletions
|
@ -671,11 +671,6 @@ return [
|
|||
'description' => 'Provided SMTP config is invalid. Please check the configured values and try again.',
|
||||
'code' => 400,
|
||||
],
|
||||
Exception::PROJECT_SMTP_CONFIG_NOT_FOUND => [
|
||||
'name' => Exception::PROJECT_SMTP_CONFIG_NOT_FOUND,
|
||||
'description' => 'SMTP configuration on project is missing. Please configure a custom SMTP server to enable custom email templates.',
|
||||
'code' => 404,
|
||||
],
|
||||
Exception::PROJECT_TEMPLATE_DEFAULT_DELETION => [
|
||||
'name' => Exception::PROJECT_TEMPLATE_DEFAULT_DELETION,
|
||||
'description' => 'You can\'t delete default template. If you are trying to reset your template changes, you can ignore this error as it\'s already been reset.',
|
||||
|
|
|
@ -54,16 +54,6 @@
|
|||
<div style="max-width:650px; word-wrap: break-wrod; overflow-wrap: break-word;
|
||||
word-break: break-all; margin:0 auto;">
|
||||
<table style="margin-top: 32px">
|
||||
<tr>
|
||||
<td>
|
||||
<h1>
|
||||
{{subject}}
|
||||
</h1>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table style="margin-top: 40px">
|
||||
<tr>
|
||||
<td>
|
||||
{{body}}
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1 +1 @@
|
|||
Subproject commit 51aa80cc80e83a41466bb353ccdff0e0e37d492f
|
||||
Subproject commit 7e31c3e34cfc1a3aa9491e634672f12e6c10be41
|
|
@ -1091,33 +1091,60 @@ App::post('/v1/account/sessions/magic-url')
|
|||
$url['query'] = Template::mergeQuery(((isset($url['query'])) ? $url['query'] : ''), ['userId' => $user->getId(), 'secret' => $loginSecret, 'expire' => $expire, 'project' => $project->getId()]);
|
||||
$url = Template::unParseURL($url);
|
||||
|
||||
$from = $project->isEmpty() || $project->getId() === 'console' ? '' : \sprintf($locale->getText('emails.sender'), $project->getAttribute('name'));
|
||||
$body = $locale->getText("emails.magicSession.body");
|
||||
$subject = $locale->getText("emails.magicSession.subject");
|
||||
|
||||
$smtpEnabled = $project->getAttribute('smtp', [])['enabled'] ?? false;
|
||||
$customTemplate = $project->getAttribute('templates', [])['email.magicSession-' . $locale->default] ?? [];
|
||||
if ($smtpEnabled && !empty($customTemplate)) {
|
||||
$body = $customTemplate['message'] ?? '';
|
||||
$subject = $customTemplate['subject'] ?? $subject;
|
||||
$from = $customTemplate['senderName'] ?? $from;
|
||||
|
||||
$smtp = $project->getAttribute('smtp', []);
|
||||
$message = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-inner-base.tpl');
|
||||
$message->setParam('{{body}}', $body);
|
||||
$body = $message->render();
|
||||
|
||||
$smtp = $project->getAttribute('smtp', []);
|
||||
$smtpEnabled = $smtp['enabled'] ?? false;
|
||||
|
||||
$senderEmail = App::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', APP_EMAIL_TEAM);
|
||||
$senderName = App::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME . ' Server');
|
||||
$replyTo = "";
|
||||
|
||||
if ($smtpEnabled) {
|
||||
if (!empty($smtp['senderEmail'])) {
|
||||
$senderEmail = $smtp['senderEmail'];
|
||||
}
|
||||
if (!empty($smtp['senderName'])) {
|
||||
$senderName = $smtp['senderName'];
|
||||
}
|
||||
if (!empty($smtp['replyTo'])) {
|
||||
$replyTo = $smtp['replyTo'];
|
||||
}
|
||||
|
||||
$mails
|
||||
->setSmtpHost($smtp['host'] ?? '')
|
||||
->setSmtpPort($smtp['port'] ?? '')
|
||||
->setSmtpUsername($smtp['username'] ?? '')
|
||||
->setSmtpPassword($smtp['password'] ?? '')
|
||||
->setSmtpSecure($smtp['secure'] ?? '')
|
||||
->setSmtpReplyTo($customTemplate['replyTo'] ?? '')
|
||||
->setSmtpSenderEmail($customTemplate['senderEmail'] ?? '')
|
||||
->setSmtpSenderName($customTemplate['senderName'] ?? '');
|
||||
} else {
|
||||
$message = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-inner-base.tpl');
|
||||
$message->setParam('{{body}}', $body);
|
||||
$body = $message->render();
|
||||
->setSmtpSecure($smtp['secure'] ?? '');
|
||||
}
|
||||
|
||||
if (!empty($customTemplate)) {
|
||||
if (!empty($customTemplate['senderEmail'])) {
|
||||
$senderEmail = $customTemplate['senderEmail'];
|
||||
}
|
||||
if (!empty($customTemplate['senderName'])) {
|
||||
$senderName = $customTemplate['senderName'];
|
||||
}
|
||||
if (!empty($customTemplate['replyTo'])) {
|
||||
$replyTo = $customTemplate['replyTo'];
|
||||
}
|
||||
|
||||
$body = $customTemplate['message'] ?? '';
|
||||
$subject = $customTemplate['subject'] ?? $subject;
|
||||
}
|
||||
|
||||
$mails
|
||||
->setSmtpReplyTo($replyTo)
|
||||
->setSmtpSenderEmail($senderEmail)
|
||||
->setSmtpSenderName($senderName);
|
||||
|
||||
$emailVariables = [
|
||||
'subject' => $subject,
|
||||
'hello' => $locale->getText("emails.magicSession.hello"),
|
||||
|
@ -1138,7 +1165,6 @@ App::post('/v1/account/sessions/magic-url')
|
|||
->setSubject($subject)
|
||||
->setBody($body)
|
||||
->setVariables($emailVariables)
|
||||
->setFrom($from)
|
||||
->setRecipient($user->getAttribute('email'))
|
||||
->trigger()
|
||||
;
|
||||
|
@ -2522,33 +2548,60 @@ App::post('/v1/account/recovery')
|
|||
$url = Template::unParseURL($url);
|
||||
|
||||
$projectName = $project->isEmpty() ? 'Console' : $project->getAttribute('name', '[APP-NAME]');
|
||||
$from = $project->isEmpty() || $project->getId() === 'console' ? '' : \sprintf($locale->getText('emails.sender'), $projectName);
|
||||
$body = $locale->getText("emails.recovery.body");
|
||||
$subject = $locale->getText("emails.recovery.subject");
|
||||
|
||||
$smtpEnabled = $project->getAttribute('smtp', [])['enabled'] ?? false;
|
||||
$customTemplate = $project->getAttribute('templates', [])['email.recovery-' . $locale->default] ?? [];
|
||||
if ($smtpEnabled && !empty($customTemplate)) {
|
||||
$body = $customTemplate['message'];
|
||||
$subject = $customTemplate['subject'] ?? $subject;
|
||||
$from = $customTemplate['senderName'] ?? $from;
|
||||
|
||||
$smtp = $project->getAttribute('smtp', []);
|
||||
$message = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-inner-base.tpl');
|
||||
$message->setParam('{{body}}', $body);
|
||||
$body = $message->render();
|
||||
|
||||
$smtp = $project->getAttribute('smtp', []);
|
||||
$smtpEnabled = $smtp['enabled'] ?? false;
|
||||
|
||||
$senderEmail = App::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', APP_EMAIL_TEAM);
|
||||
$senderName = App::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME . ' Server');
|
||||
$replyTo = "";
|
||||
|
||||
if ($smtpEnabled) {
|
||||
if (!empty($smtp['senderEmail'])) {
|
||||
$senderEmail = $smtp['senderEmail'];
|
||||
}
|
||||
if (!empty($smtp['senderName'])) {
|
||||
$senderName = $smtp['senderName'];
|
||||
}
|
||||
if (!empty($smtp['replyTo'])) {
|
||||
$replyTo = $smtp['replyTo'];
|
||||
}
|
||||
|
||||
$mails
|
||||
->setSmtpHost($smtp['host'] ?? '')
|
||||
->setSmtpPort($smtp['port'] ?? '')
|
||||
->setSmtpUsername($smtp['username'] ?? '')
|
||||
->setSmtpPassword($smtp['password'] ?? '')
|
||||
->setSmtpSecure($smtp['secure'] ?? '')
|
||||
->setSmtpReplyTo($customTemplate['replyTo'] ?? '')
|
||||
->setSmtpSenderEmail($customTemplate['senderEmail'] ?? '')
|
||||
->setSmtpSenderName($customTemplate['senderName'] ?? '');
|
||||
} else {
|
||||
$message = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-inner-base.tpl');
|
||||
$message->setParam('{{body}}', $body);
|
||||
$body = $message->render();
|
||||
->setSmtpSecure($smtp['secure'] ?? '');
|
||||
}
|
||||
|
||||
if (!empty($customTemplate)) {
|
||||
if (!empty($customTemplate['senderEmail'])) {
|
||||
$senderEmail = $customTemplate['senderEmail'];
|
||||
}
|
||||
if (!empty($customTemplate['senderName'])) {
|
||||
$senderName = $customTemplate['senderName'];
|
||||
}
|
||||
if (!empty($customTemplate['replyTo'])) {
|
||||
$replyTo = $customTemplate['replyTo'];
|
||||
}
|
||||
|
||||
$body = $customTemplate['message'] ?? '';
|
||||
$subject = $customTemplate['subject'] ?? $subject;
|
||||
}
|
||||
|
||||
$mails
|
||||
->setSmtpReplyTo($replyTo)
|
||||
->setSmtpSenderEmail($senderEmail)
|
||||
->setSmtpSenderName($senderName);
|
||||
|
||||
$emailVariables = [
|
||||
'subject' => $subject,
|
||||
'hello' => $locale->getText("emails.recovery.hello"),
|
||||
|
@ -2571,7 +2624,6 @@ App::post('/v1/account/recovery')
|
|||
->setName($profile->getAttribute('name'))
|
||||
->setBody($body)
|
||||
->setVariables($emailVariables)
|
||||
->setFrom($from)
|
||||
->setSubject($subject)
|
||||
->trigger();
|
||||
;
|
||||
|
@ -2747,33 +2799,60 @@ App::post('/v1/account/verification')
|
|||
$url = Template::unParseURL($url);
|
||||
|
||||
$projectName = $project->isEmpty() ? 'Console' : $project->getAttribute('name', '[APP-NAME]');
|
||||
$from = $project->isEmpty() || $project->getId() === 'console' ? '' : \sprintf($locale->getText('emails.sender'), $projectName);
|
||||
$body = $locale->getText("emails.verification.body");
|
||||
$subject = $locale->getText("emails.verification.subject");
|
||||
|
||||
$smtpEnabled = $project->getAttribute('smtp', [])['enabled'] ?? false;
|
||||
$customTemplate = $project->getAttribute('templates', [])['email.verification-' . $locale->default] ?? [];
|
||||
if ($smtpEnabled && !empty($customTemplate)) {
|
||||
$body = $customTemplate['message'] ?? '';
|
||||
$subject = $customTemplate['subject'] ?? $subject;
|
||||
$from = $customTemplate['senderName'] ?? $from;
|
||||
|
||||
$smtp = $project->getAttribute('smtp', []);
|
||||
$message = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-inner-base.tpl');
|
||||
$message->setParam('{{body}}', $body);
|
||||
$body = $message->render();
|
||||
|
||||
$smtp = $project->getAttribute('smtp', []);
|
||||
$smtpEnabled = $smtp['enabled'] ?? false;
|
||||
|
||||
$senderEmail = App::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', APP_EMAIL_TEAM);
|
||||
$senderName = App::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME . ' Server');
|
||||
$replyTo = "";
|
||||
|
||||
if ($smtpEnabled) {
|
||||
if (!empty($smtp['senderEmail'])) {
|
||||
$senderEmail = $smtp['senderEmail'];
|
||||
}
|
||||
if (!empty($smtp['senderName'])) {
|
||||
$senderName = $smtp['senderName'];
|
||||
}
|
||||
if (!empty($smtp['replyTo'])) {
|
||||
$replyTo = $smtp['replyTo'];
|
||||
}
|
||||
|
||||
$mails
|
||||
->setSmtpHost($smtp['host'] ?? '')
|
||||
->setSmtpPort($smtp['port'] ?? '')
|
||||
->setSmtpUsername($smtp['username'] ?? '')
|
||||
->setSmtpPassword($smtp['password'] ?? '')
|
||||
->setSmtpSecure($smtp['secure'] ?? '')
|
||||
->setSmtpReplyTo($customTemplate['replyTo'] ?? '')
|
||||
->setSmtpSenderEmail($customTemplate['senderEmail'] ?? '')
|
||||
->setSmtpSenderName($customTemplate['senderName'] ?? '');
|
||||
} else {
|
||||
$message = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-inner-base.tpl');
|
||||
$message->setParam('{{body}}', $body);
|
||||
$body = $message->render();
|
||||
->setSmtpSecure($smtp['secure'] ?? '');
|
||||
}
|
||||
|
||||
if (!empty($customTemplate)) {
|
||||
if (!empty($customTemplate['senderEmail'])) {
|
||||
$senderEmail = $customTemplate['senderEmail'];
|
||||
}
|
||||
if (!empty($customTemplate['senderName'])) {
|
||||
$senderName = $customTemplate['senderName'];
|
||||
}
|
||||
if (!empty($customTemplate['replyTo'])) {
|
||||
$replyTo = $customTemplate['replyTo'];
|
||||
}
|
||||
|
||||
$body = $customTemplate['message'] ?? '';
|
||||
$subject = $customTemplate['subject'] ?? $subject;
|
||||
}
|
||||
|
||||
$mails
|
||||
->setSmtpReplyTo($replyTo)
|
||||
->setSmtpSenderEmail($senderEmail)
|
||||
->setSmtpSenderName($senderName);
|
||||
|
||||
$emailVariables = [
|
||||
'subject' => $subject,
|
||||
'hello' => $locale->getText("emails.verification.hello"),
|
||||
|
@ -2794,7 +2873,6 @@ App::post('/v1/account/verification')
|
|||
->setSubject($subject)
|
||||
->setBody($body)
|
||||
->setVariables($emailVariables)
|
||||
->setFrom($from)
|
||||
->setRecipient($user->getAttribute('email'))
|
||||
->setName($user->getAttribute('name') ?? '')
|
||||
->trigger()
|
||||
|
|
|
@ -29,6 +29,10 @@ App::get('/v1/console/variables')
|
|||
->label('sdk.response.model', Response::MODEL_CONSOLE_VARIABLES)
|
||||
->inject('response')
|
||||
->action(function (Response $response) {
|
||||
$isDomainEnabled = !empty(App::getEnv('_APP_DOMAIN', ''))
|
||||
&& !empty(App::getEnv('_APP_DOMAIN_TARGET', ''))
|
||||
&& App::getEnv('_APP_DOMAIN', '') !== 'localhost'
|
||||
&& App::getEnv('_APP_DOMAIN_TARGET', '') !== 'localhost';
|
||||
|
||||
$isVcsEnabled = !empty(App::getEnv('_APP_VCS_GITHUB_APP_NAME', ''))
|
||||
&& !empty(App::getEnv('_APP_VCS_GITHUB_PRIVATE_KEY', ''))
|
||||
|
@ -44,6 +48,7 @@ App::get('/v1/console/variables')
|
|||
'_APP_FUNCTIONS_SIZE_LIMIT' => +App::getEnv('_APP_FUNCTIONS_SIZE_LIMIT'),
|
||||
'_APP_USAGE_STATS' => App::getEnv('_APP_USAGE_STATS'),
|
||||
'_APP_VCS_ENABLED' => $isVcsEnabled,
|
||||
'_APP_DOMAIN_ENABLED' => $isDomainEnabled,
|
||||
'_APP_ASSISTANT_ENABLED' => $isAssistantEnabled
|
||||
]);
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ App::post('/v1/projects')
|
|||
->param('projectId', '', new ProjectId(), 'Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, and hyphen. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('name', null, new Text(128), 'Project name. Max length: 128 chars.')
|
||||
->param('teamId', '', new UID(), 'Team unique ID.')
|
||||
->param('region', App::getEnv('_APP_REGION', 'default'), new Whitelist(array_keys(array_filter(Config::getParam('regions'), fn($config) => !$config['disabled']))), 'Project Region.', true)
|
||||
->param('region', App::getEnv('_APP_REGION', 'default'), new Whitelist(array_keys(array_filter(Config::getParam('regions'), fn ($config) => !$config['disabled']))), 'Project Region.', true)
|
||||
->param('description', '', new Text(256), 'Project description. Max length: 256 chars.', true)
|
||||
->param('logo', '', new Text(1024), 'Project logo.', true)
|
||||
->param('url', '', new URL(), 'Project URL.', true)
|
||||
|
@ -436,17 +436,17 @@ App::patch('/v1/projects/:projectId')
|
|||
}
|
||||
|
||||
$project = $dbForConsole->updateDocument('projects', $project->getId(), $project
|
||||
->setAttribute('name', $name)
|
||||
->setAttribute('description', $description)
|
||||
->setAttribute('logo', $logo)
|
||||
->setAttribute('url', $url)
|
||||
->setAttribute('legalName', $legalName)
|
||||
->setAttribute('legalCountry', $legalCountry)
|
||||
->setAttribute('legalState', $legalState)
|
||||
->setAttribute('legalCity', $legalCity)
|
||||
->setAttribute('legalAddress', $legalAddress)
|
||||
->setAttribute('legalTaxId', $legalTaxId)
|
||||
->setAttribute('search', implode(' ', [$projectId, $name])));
|
||||
->setAttribute('name', $name)
|
||||
->setAttribute('description', $description)
|
||||
->setAttribute('logo', $logo)
|
||||
->setAttribute('url', $url)
|
||||
->setAttribute('legalName', $legalName)
|
||||
->setAttribute('legalCountry', $legalCountry)
|
||||
->setAttribute('legalState', $legalState)
|
||||
->setAttribute('legalCity', $legalCity)
|
||||
->setAttribute('legalAddress', $legalAddress)
|
||||
->setAttribute('legalTaxId', $legalTaxId)
|
||||
->setAttribute('search', implode(' ', [$projectId, $name])));
|
||||
|
||||
$response->dynamic($project, Response::MODEL_PROJECT);
|
||||
});
|
||||
|
@ -479,14 +479,14 @@ App::patch('/v1/projects/:projectId/team')
|
|||
}
|
||||
|
||||
$project = $dbForConsole->updateDocument('projects', $project->getId(), $project
|
||||
->setAttribute('teamId', $teamId)
|
||||
->setAttribute('$permissions', [
|
||||
Permission::read(Role::team(ID::custom($teamId))),
|
||||
Permission::update(Role::team(ID::custom($teamId), 'owner')),
|
||||
Permission::update(Role::team(ID::custom($teamId), 'developer')),
|
||||
Permission::delete(Role::team(ID::custom($teamId), 'owner')),
|
||||
Permission::delete(Role::team(ID::custom($teamId), 'developer')),
|
||||
]));
|
||||
->setAttribute('teamId', $teamId)
|
||||
->setAttribute('$permissions', [
|
||||
Permission::read(Role::team(ID::custom($teamId))),
|
||||
Permission::update(Role::team(ID::custom($teamId), 'owner')),
|
||||
Permission::update(Role::team(ID::custom($teamId), 'developer')),
|
||||
Permission::delete(Role::team(ID::custom($teamId), 'owner')),
|
||||
Permission::delete(Role::team(ID::custom($teamId), 'developer')),
|
||||
]));
|
||||
|
||||
$response->dynamic($project, Response::MODEL_PROJECT);
|
||||
});
|
||||
|
@ -502,7 +502,7 @@ App::patch('/v1/projects/:projectId/service')
|
|||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_PROJECT)
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('service', '', new WhiteList(array_keys(array_filter(Config::getParam('services'), fn($element) => $element['optional'])), true), 'Service name.')
|
||||
->param('service', '', new WhiteList(array_keys(array_filter(Config::getParam('services'), fn ($element) => $element['optional'])), true), 'Service name.')
|
||||
->param('status', null, new Boolean(), 'Service status.')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
|
@ -544,7 +544,7 @@ App::patch('/v1/projects/:projectId/service/all')
|
|||
throw new Exception(Exception::PROJECT_NOT_FOUND);
|
||||
}
|
||||
|
||||
$allServices = array_keys(array_filter(Config::getParam('services'), fn($element) => $element['optional']));
|
||||
$allServices = array_keys(array_filter(Config::getParam('services'), fn ($element) => $element['optional']));
|
||||
|
||||
$services = [];
|
||||
foreach ($allServices as $service) {
|
||||
|
@ -843,8 +843,7 @@ App::delete('/v1/projects/:projectId')
|
|||
|
||||
$deletes
|
||||
->setType(DELETE_TYPE_DOCUMENT)
|
||||
->setDocument($project)
|
||||
;
|
||||
->setDocument($project);
|
||||
|
||||
if (!$dbForConsole->deleteDocument('projects', $projectId)) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove project from DB');
|
||||
|
@ -1022,8 +1021,7 @@ App::put('/v1/projects/:projectId/webhooks/:webhookId')
|
|||
->setAttribute('url', $url)
|
||||
->setAttribute('security', $security)
|
||||
->setAttribute('httpUser', $httpUser)
|
||||
->setAttribute('httpPass', $httpPass)
|
||||
;
|
||||
->setAttribute('httpPass', $httpPass);
|
||||
|
||||
$dbForConsole->updateDocument('webhooks', $webhook->getId(), $webhook);
|
||||
$dbForConsole->deleteCachedDocument('projects', $project->getId());
|
||||
|
@ -1262,8 +1260,7 @@ App::put('/v1/projects/:projectId/keys/:keyId')
|
|||
$key
|
||||
->setAttribute('name', $name)
|
||||
->setAttribute('scopes', $scopes)
|
||||
->setAttribute('expire', $expire)
|
||||
;
|
||||
->setAttribute('expire', $expire);
|
||||
|
||||
$dbForConsole->updateDocument('keys', $key->getId(), $key);
|
||||
|
||||
|
@ -1465,8 +1462,7 @@ App::put('/v1/projects/:projectId/platforms/:platformId')
|
|||
->setAttribute('name', $name)
|
||||
->setAttribute('key', $key)
|
||||
->setAttribute('store', $store)
|
||||
->setAttribute('hostname', $hostname)
|
||||
;
|
||||
->setAttribute('hostname', $hostname);
|
||||
|
||||
$dbForConsole->updateDocument('platforms', $platform->getId(), $platform);
|
||||
|
||||
|
@ -1525,15 +1521,17 @@ App::patch('/v1/projects/:projectId/smtp')
|
|||
->label('sdk.response.model', Response::MODEL_PROJECT)
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('enabled', false, new Boolean(), 'Enable custom SMTP service')
|
||||
->param('sender', '', new Email(), 'SMTP sender email')
|
||||
->param('host', '', new HostName(), 'SMTP server host name')
|
||||
->param('port', null, new Integer(), 'SMTP server port')
|
||||
->param('username', null, new Text(0), 'SMTP server username')
|
||||
->param('password', null, new Text(0), 'SMTP server password')
|
||||
->param('senderName', '', new Text(255, 0), 'Name of the email sender', true)
|
||||
->param('senderEmail', '', new Email(), 'Email of the sender', true)
|
||||
->param('replyTo', '', new Email(), 'Reply to email', true)
|
||||
->param('host', '', new HostName(), 'SMTP server host name', true)
|
||||
->param('port', 587, new Integer(), 'SMTP server port', true)
|
||||
->param('username', '', new Text(0), 'SMTP server username', true)
|
||||
->param('password', '', new Text(0), 'SMTP server password', true)
|
||||
->param('secure', '', new WhiteList(['tls'], true), 'Does SMTP server use secure connection', true)
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, bool $enabled, string $sender, string $host, int $port, string $username, string $password, string $secure, Response $response, Database $dbForConsole) {
|
||||
->action(function (string $projectId, bool $enabled, string $senderName, string $senderEmail, string $replyTo, string $host, int $port, string $username, string $password, string $secure, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
|
@ -1541,36 +1539,64 @@ App::patch('/v1/projects/:projectId/smtp')
|
|||
throw new Exception(Exception::PROJECT_NOT_FOUND);
|
||||
}
|
||||
|
||||
// validate SMTP settings
|
||||
$mail = new PHPMailer(true);
|
||||
$mail->isSMTP();
|
||||
$mail->Username = $username;
|
||||
$mail->Password = $password;
|
||||
$mail->Host = $host;
|
||||
$mail->Port = $port;
|
||||
$mail->SMTPSecure = $secure;
|
||||
$mail->SMTPAutoTLS = false;
|
||||
$mail->Timeout = 5;
|
||||
|
||||
try {
|
||||
$valid = $mail->SmtpConnect();
|
||||
|
||||
if (!$valid) {
|
||||
throw new Exception('Connection is not valid.');
|
||||
// Ensure required params for when enabling SMTP
|
||||
if ($enabled) {
|
||||
if (empty($senderName)) {
|
||||
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'Sender name is required when enabling SMTP.');
|
||||
} elseif (empty($senderEmail)) {
|
||||
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'Sender email is required when enabling SMTP.');
|
||||
} elseif (empty($host)) {
|
||||
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'Host is required when enabling SMTP.');
|
||||
} elseif (empty($port)) {
|
||||
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'Port is required when enabling SMTP.');
|
||||
} elseif (empty($username)) {
|
||||
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'Username is required when enabling SMTP.');
|
||||
} elseif (empty($password)) {
|
||||
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'Password is required when enabling SMTP.');
|
||||
}
|
||||
} catch (Throwable $error) {
|
||||
throw new Exception(Exception::PROJECT_SMTP_CONFIG_INVALID, 'Could not connect to SMTP server: ' . $error->getMessage());
|
||||
}
|
||||
|
||||
$smtp = [
|
||||
'enabled' => $enabled,
|
||||
'sender' => $sender,
|
||||
'host' => $host,
|
||||
'port' => $port,
|
||||
'username' => $username,
|
||||
'password' => $password,
|
||||
'secure' => $secure,
|
||||
];
|
||||
// validate SMTP settings
|
||||
if ($enabled) {
|
||||
$mail = new PHPMailer(true);
|
||||
$mail->isSMTP();
|
||||
$mail->Username = $username;
|
||||
$mail->Password = $password;
|
||||
$mail->Host = $host;
|
||||
$mail->Port = $port;
|
||||
$mail->SMTPSecure = $secure;
|
||||
$mail->SMTPAutoTLS = false;
|
||||
$mail->Timeout = 5;
|
||||
|
||||
try {
|
||||
$valid = $mail->SmtpConnect();
|
||||
|
||||
if (!$valid) {
|
||||
throw new Exception('Connection is not valid.');
|
||||
}
|
||||
} catch (Throwable $error) {
|
||||
throw new Exception(Exception::PROJECT_SMTP_CONFIG_INVALID, 'Could not connect to SMTP server: ' . $error->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// Save SMTP settings
|
||||
if ($enabled) {
|
||||
$smtp = [
|
||||
'enabled' => $enabled,
|
||||
'senderName' => $senderName,
|
||||
'senderEmail' => $senderEmail,
|
||||
'replyTo' => $replyTo,
|
||||
'host' => $host,
|
||||
'port' => $port,
|
||||
'username' => $username,
|
||||
'password' => $password,
|
||||
'secure' => $secure,
|
||||
];
|
||||
} else {
|
||||
$smtp = [
|
||||
'enabled' => false
|
||||
];
|
||||
}
|
||||
|
||||
$project = $dbForConsole->updateDocument('projects', $project->getId(), $project->setAttribute('smtp', $smtp));
|
||||
|
||||
|
@ -1589,7 +1615,7 @@ App::get('/v1/projects/:projectId/templates/sms/:type/:locale')
|
|||
->label('sdk.response.model', Response::MODEL_SMS_TEMPLATE)
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('type', '', new WhiteList(Config::getParam('locale-templates')['sms'] ?? []), 'Template type')
|
||||
->param('locale', '', fn($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes'])
|
||||
->param('locale', '', fn ($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes'])
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $type, string $locale, Response $response, Database $dbForConsole) {
|
||||
|
@ -1607,7 +1633,7 @@ App::get('/v1/projects/:projectId/templates/sms/:type/:locale')
|
|||
|
||||
if (is_null($template)) {
|
||||
$template = [
|
||||
'message' => Template::fromFile(__DIR__ . '/../../config/locale/templates/sms-base.tpl')->render(),
|
||||
'message' => Template::fromFile(__DIR__ . '/../../config/locale/templates/sms-base.tpl')->render(),
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -1629,7 +1655,7 @@ App::get('/v1/projects/:projectId/templates/email/:type/:locale')
|
|||
->label('sdk.response.model', Response::MODEL_EMAIL_TEMPLATE)
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('type', '', new WhiteList(Config::getParam('locale-templates')['email'] ?? []), 'Template type')
|
||||
->param('locale', '', fn($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes'])
|
||||
->param('locale', '', fn ($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes'])
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $type, string $locale, Response $response, Database $dbForConsole) {
|
||||
|
@ -1656,13 +1682,11 @@ App::get('/v1/projects/:projectId/templates/email/:type/:locale')
|
|||
->setParam('{{direction}}', $localeObj->getText('settings.direction'));
|
||||
$message = $message->render();
|
||||
|
||||
$from = $project->isEmpty() || $project->getId() === 'console' ? '' : \sprintf($localeObj->getText('emails.sender'), $project->getAttribute('name'));
|
||||
$from = empty($from) ? \urldecode(App::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME . ' Server')) : $from;
|
||||
$template = [
|
||||
'message' => $message,
|
||||
'subject' => $localeObj->getText('emails.' . $type . '.subject'),
|
||||
'senderEmail' => App::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', ''),
|
||||
'senderName' => $from
|
||||
'senderEmail' => '',
|
||||
'senderName' => ''
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -1684,7 +1708,7 @@ App::patch('/v1/projects/:projectId/templates/sms/:type/:locale')
|
|||
->label('sdk.response.model', Response::MODEL_SMS_TEMPLATE)
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('type', '', new WhiteList(Config::getParam('locale-templates')['sms'] ?? []), 'Template type')
|
||||
->param('locale', '', fn($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes'])
|
||||
->param('locale', '', fn ($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes'])
|
||||
->param('message', '', new Text(0), 'Template message')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
|
@ -1698,8 +1722,6 @@ App::patch('/v1/projects/:projectId/templates/sms/:type/:locale')
|
|||
throw new Exception(Exception::PROJECT_NOT_FOUND);
|
||||
}
|
||||
|
||||
// TODO: Ensure SMS is enabled on project
|
||||
|
||||
$templates = $project->getAttribute('templates', []);
|
||||
$templates['sms.' . $type . '-' . $locale] = [
|
||||
'message' => $message
|
||||
|
@ -1726,15 +1748,15 @@ App::patch('/v1/projects/:projectId/templates/email/:type/:locale')
|
|||
->label('sdk.response.model', Response::MODEL_PROJECT)
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('type', '', new WhiteList(Config::getParam('locale-templates')['email'] ?? []), 'Template type')
|
||||
->param('locale', '', fn($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes'])
|
||||
->param('senderName', '', new Text(255), 'Name of the email sender')
|
||||
->param('senderEmail', '', new Email(), 'Email of the sender')
|
||||
->param('locale', '', fn ($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes'])
|
||||
->param('subject', '', new Text(255), 'Email Subject')
|
||||
->param('message', '', new Text(0), 'Template message')
|
||||
->param('senderName', '', new Text(255, 0), 'Name of the email sender', true)
|
||||
->param('senderEmail', '', new Email(), 'Email of the sender', true)
|
||||
->param('replyTo', '', new Email(), 'Reply to email', true)
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $type, string $locale, string $senderName, string $senderEmail, string $subject, string $message, string $replyTo, Response $response, Database $dbForConsole) {
|
||||
->action(function (string $projectId, string $type, string $locale, string $subject, string $message, string $senderName, string $senderEmail, string $replyTo, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
|
@ -1742,11 +1764,6 @@ App::patch('/v1/projects/:projectId/templates/email/:type/:locale')
|
|||
throw new Exception(Exception::PROJECT_NOT_FOUND);
|
||||
}
|
||||
|
||||
$smtpEnabled = $project->getAttribute('smtp', [])['enabled'] ?? false;
|
||||
if (!$smtpEnabled) {
|
||||
throw new Exception(Exception::PROJECT_SMTP_CONFIG_NOT_FOUND);
|
||||
}
|
||||
|
||||
$templates = $project->getAttribute('templates', []);
|
||||
$templates['email.' . $type . '-' . $locale] = [
|
||||
'senderName' => $senderName,
|
||||
|
@ -1781,7 +1798,7 @@ App::delete('/v1/projects/:projectId/templates/sms/:type/:locale')
|
|||
->label('sdk.response.model', Response::MODEL_SMS_TEMPLATE)
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('type', '', new WhiteList(Config::getParam('locale-templates')['sms'] ?? []), 'Template type')
|
||||
->param('locale', '', fn($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes'])
|
||||
->param('locale', '', fn ($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes'])
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $type, string $locale, Response $response, Database $dbForConsole) {
|
||||
|
@ -1824,7 +1841,7 @@ App::delete('/v1/projects/:projectId/templates/email/:type/:locale')
|
|||
->label('sdk.response.model', Response::MODEL_EMAIL_TEMPLATE)
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('type', '', new WhiteList(Config::getParam('locale-templates')['email'] ?? []), 'Template type')
|
||||
->param('locale', '', fn($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes'])
|
||||
->param('locale', '', fn ($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes'])
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $type, string $locale, Response $response, Database $dbForConsole) {
|
||||
|
|
|
@ -543,33 +543,60 @@ App::post('/v1/teams/:teamId/memberships')
|
|||
if (!empty($email)) {
|
||||
$projectName = $project->isEmpty() ? 'Console' : $project->getAttribute('name', '[APP-NAME]');
|
||||
|
||||
$from = $project->isEmpty() || $project->getId() === 'console' ? '' : \sprintf($locale->getText('emails.sender'), $projectName);
|
||||
$body = $locale->getText("emails.invitation.body");
|
||||
$subject = \sprintf($locale->getText("emails.invitation.subject"), $team->getAttribute('name'), $projectName);
|
||||
|
||||
$smtpEnabled = $project->getAttribute('smtp', [])['enabled'] ?? false;
|
||||
$customTemplate = $project->getAttribute('templates', [])['email.invitation-' . $locale->default] ?? [];
|
||||
if ($smtpEnabled && !empty($customTemplate)) {
|
||||
$body = Template::fromString($customTemplate['message'] ?? '');
|
||||
$subject = $customTemplate['subject'] ?? $subject;
|
||||
$from = $customTemplate['senderName'] ?? $from;
|
||||
|
||||
$smtp = $project->getAttribute('smtp', []);
|
||||
$message = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-inner-base.tpl');
|
||||
$message->setParam('{{body}}', $body);
|
||||
$body = $message->render();
|
||||
|
||||
$smtp = $project->getAttribute('smtp', []);
|
||||
$smtpEnabled = $smtp['enabled'] ?? false;
|
||||
|
||||
$senderEmail = App::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', APP_EMAIL_TEAM);
|
||||
$senderName = App::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME . ' Server');
|
||||
$replyTo = "";
|
||||
|
||||
if ($smtpEnabled) {
|
||||
if (!empty($smtp['senderEmail'])) {
|
||||
$senderEmail = $smtp['senderEmail'];
|
||||
}
|
||||
if (!empty($smtp['senderName'])) {
|
||||
$senderName = $smtp['senderName'];
|
||||
}
|
||||
if (!empty($smtp['replyTo'])) {
|
||||
$replyTo = $smtp['replyTo'];
|
||||
}
|
||||
|
||||
$mails
|
||||
->setSmtpHost($smtp['host'] ?? '')
|
||||
->setSmtpPort($smtp['port'] ?? '')
|
||||
->setSmtpUsername($smtp['username'] ?? '')
|
||||
->setSmtpPassword($smtp['password'] ?? '')
|
||||
->setSmtpSecure($smtp['secure'] ?? '')
|
||||
->setSmtpReplyTo($customTemplate['replyTo'] ?? '')
|
||||
->setSmtpSenderEmail($customTemplate['senderEmail'] ?? '')
|
||||
->setSmtpSenderName($customTemplate['senderName'] ?? '');
|
||||
} else {
|
||||
$message = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-inner-base.tpl');
|
||||
$message->setParam('{{body}}', $body);
|
||||
$body = $message->render();
|
||||
->setSmtpSecure($smtp['secure'] ?? '');
|
||||
}
|
||||
|
||||
if (!empty($customTemplate)) {
|
||||
if (!empty($customTemplate['senderEmail'])) {
|
||||
$senderEmail = $customTemplate['senderEmail'];
|
||||
}
|
||||
if (!empty($customTemplate['senderName'])) {
|
||||
$senderName = $customTemplate['senderName'];
|
||||
}
|
||||
if (!empty($customTemplate['replyTo'])) {
|
||||
$replyTo = $customTemplate['replyTo'];
|
||||
}
|
||||
|
||||
$body = $customTemplate['message'] ?? '';
|
||||
$subject = $customTemplate['subject'] ?? $subject;
|
||||
}
|
||||
|
||||
$mails
|
||||
->setSmtpReplyTo($replyTo)
|
||||
->setSmtpSenderEmail($senderEmail)
|
||||
->setSmtpSenderName($senderName);
|
||||
|
||||
$emailVariables = [
|
||||
'owner' => $user->getAttribute('name'),
|
||||
'team' => $team->getAttribute('name'),
|
||||
|
@ -591,7 +618,6 @@ App::post('/v1/teams/:teamId/memberships')
|
|||
$mails
|
||||
->setSubject($subject)
|
||||
->setBody($body)
|
||||
->setFrom($from)
|
||||
->setRecipient($invitee->getAttribute('email'))
|
||||
->setName($invitee->getAttribute('name'))
|
||||
->setVariables($emailVariables)
|
||||
|
|
|
@ -38,7 +38,6 @@ class MailsV1 extends Worker
|
|||
$name = $this->args['name'];
|
||||
$body = $this->args['body'];
|
||||
$variables = $this->args['variables'];
|
||||
$from = $this->args['from'];
|
||||
|
||||
$body = Template::fromFile(__DIR__ . '/../config/locale/templates/email-base.tpl');
|
||||
|
||||
|
@ -62,6 +61,11 @@ class MailsV1 extends Worker
|
|||
$mail->Body = $body;
|
||||
$mail->AltBody = \strip_tags($body);
|
||||
|
||||
$mail->setFrom($smtp['senderEmail'], $smtp['senderName']);
|
||||
if (!empty($smtp['replyTo'])) {
|
||||
$mail->addReplyTo($smtp['replyTo'], $smtp['senderName']);
|
||||
}
|
||||
|
||||
try {
|
||||
$mail->send();
|
||||
} catch (\Exception $error) {
|
||||
|
@ -88,12 +92,6 @@ class MailsV1 extends Worker
|
|||
$mail->SMTPAutoTLS = false;
|
||||
$mail->CharSet = 'UTF-8';
|
||||
|
||||
$from = \urldecode($smtp['senderName'] ?? App::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME . ' Server'));
|
||||
$email = $smtp['senderEmail'] ?? App::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', APP_EMAIL_TEAM);
|
||||
|
||||
$mail->setFrom($email, $from);
|
||||
$mail->addReplyTo($email, $from);
|
||||
|
||||
$mail->isHTML(true);
|
||||
|
||||
return $mail;
|
||||
|
|
|
@ -8,7 +8,6 @@ use Utopia\Database\Document;
|
|||
class Mail extends Event
|
||||
{
|
||||
protected string $recipient = '';
|
||||
protected string $from = '';
|
||||
protected string $name = '';
|
||||
protected string $subject = '';
|
||||
protected string $body = '';
|
||||
|
@ -66,29 +65,6 @@ class Mail extends Event
|
|||
return $this->recipient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets from for the mail event.
|
||||
*
|
||||
* @param string $from
|
||||
* @return self
|
||||
*/
|
||||
public function setFrom(string $from): self
|
||||
{
|
||||
$this->from = $from;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns from for mail event.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getFrom(): string
|
||||
{
|
||||
return $this->from;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets body for the mail event.
|
||||
*
|
||||
|
@ -342,7 +318,6 @@ class Mail extends Event
|
|||
public function trigger(): string|bool
|
||||
{
|
||||
return Resque::enqueue($this->queue, $this->class, [
|
||||
'from' => $this->from,
|
||||
'recipient' => $this->recipient,
|
||||
'name' => $this->name,
|
||||
'subject' => $this->subject,
|
||||
|
|
|
@ -189,7 +189,6 @@ class Exception extends \Exception
|
|||
public const PROJECT_KEY_EXPIRED = 'project_key_expired';
|
||||
|
||||
public const PROJECT_SMTP_CONFIG_INVALID = 'project_smtp_config_invalid';
|
||||
public const PROJECT_SMTP_CONFIG_NOT_FOUND = 'project_smtp_config_not_found';
|
||||
|
||||
public const PROJECT_TEMPLATE_DEFAULT_DELETION = 'project_template_default_deletion';
|
||||
|
||||
|
|
|
@ -40,6 +40,12 @@ class ConsoleVariables extends Model
|
|||
'default' => false,
|
||||
'example' => true,
|
||||
])
|
||||
->addRule('_APP_DOMAIN_ENABLED', [
|
||||
'type' => self::TYPE_BOOLEAN,
|
||||
'description' => 'Defines if main domain is configured. If so, custom domains can be created.',
|
||||
'default' => false,
|
||||
'example' => true,
|
||||
])
|
||||
->addRule('_APP_ASSISTANT_ENABLED', [
|
||||
'type' => self::TYPE_BOOLEAN,
|
||||
'description' => 'Defines if AI assistant is enabled.',
|
||||
|
|
|
@ -173,12 +173,24 @@ class Project extends Model
|
|||
'example' => false,
|
||||
'array' => false
|
||||
])
|
||||
->addRule('smtpSender', [
|
||||
->addRule('smtpSenderName', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'SMTP sender name',
|
||||
'default' => '',
|
||||
'example' => 'John Appwrite',
|
||||
])
|
||||
->addRule('smtpSenderEmail', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'SMTP sender email',
|
||||
'default' => '',
|
||||
'example' => 'john@appwrite.io',
|
||||
])
|
||||
->addRule('smtpReplyTo', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'SMTP reply to email',
|
||||
'default' => '',
|
||||
'example' => 'support@appwrite.io',
|
||||
])
|
||||
->addRule('smtpHost', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'SMTP server host name',
|
||||
|
@ -277,7 +289,9 @@ class Project extends Model
|
|||
// SMTP
|
||||
$smtp = $document->getAttribute('smtp', []);
|
||||
$document->setAttribute('smtpEnabled', $smtp['enabled'] ?? false);
|
||||
$document->setAttribute('smtpSender', $smtp['sender'] ?? '');
|
||||
$document->setAttribute('smtpSenderEmail', $smtp['senderEmail'] ?? '');
|
||||
$document->setAttribute('smtpSenderName', $smtp['senderName'] ?? '');
|
||||
$document->setAttribute('smtpReplyTo', $smtp['replyTo'] ?? '');
|
||||
$document->setAttribute('smtpHost', $smtp['host'] ?? '');
|
||||
$document->setAttribute('smtpPort', $smtp['port'] ?? '');
|
||||
$document->setAttribute('smtpUsername', $smtp['username'] ?? '');
|
||||
|
|
Loading…
Reference in a new issue