Core Update 1.4.0
This commit is contained in:
@@ -25,6 +25,7 @@ namespace Api {
|
||||
$connectionData = new ConnectionData($host, $port, $login, $password);
|
||||
$connectionData->setProperty("from", $settings["mail_from"] ?? "");
|
||||
$connectionData->setProperty("last_sync", $settings["mail_last_sync"] ?? "");
|
||||
$connectionData->setProperty("mail_footer", $settings["mail_footer"] ?? "");
|
||||
return $connectionData;
|
||||
}
|
||||
|
||||
@@ -41,22 +42,20 @@ namespace Api\Mail {
|
||||
use DateTimeInterface;
|
||||
use Driver\SQL\Column\Column;
|
||||
use Driver\SQL\Condition\Compare;
|
||||
use Driver\SQL\Condition\CondBool;
|
||||
use Driver\SQL\Condition\CondIn;
|
||||
use Driver\SQL\Condition\CondNot;
|
||||
use Driver\SQL\Expression\CurrentTimeStamp;
|
||||
use Driver\SQL\Expression\JsonArrayAgg;
|
||||
use Driver\SQL\Strategy\UpdateStrategy;
|
||||
use External\PHPMailer\Exception;
|
||||
use External\PHPMailer\PHPMailer;
|
||||
use Objects\ConnectionData;
|
||||
use Objects\GpgKey;
|
||||
use Objects\User;
|
||||
|
||||
class Test extends MailAPI {
|
||||
|
||||
public function __construct(User $user, bool $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array(
|
||||
"receiver" => new Parameter("receiver", Parameter::TYPE_EMAIL)
|
||||
"receiver" => new Parameter("receiver", Parameter::TYPE_EMAIL),
|
||||
"gpgFingerprint" => new StringType("gpgFingerprint", 64, true, null)
|
||||
));
|
||||
}
|
||||
|
||||
@@ -70,7 +69,9 @@ namespace Api\Mail {
|
||||
$this->success = $req->execute(array(
|
||||
"to" => $receiver,
|
||||
"subject" => "Test E-Mail",
|
||||
"body" => "Hey! If you receive this e-mail, your mail configuration seems to be working."
|
||||
"body" => "Hey! If you receive this e-mail, your mail configuration seems to be working.",
|
||||
"gpgFingerprint" => $this->getParam("gpgFingerprint"),
|
||||
"asnyc" => false
|
||||
));
|
||||
|
||||
$this->lastError = $req->getLastError();
|
||||
@@ -78,6 +79,7 @@ namespace Api\Mail {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: expired gpg keys?
|
||||
class Send extends MailAPI {
|
||||
public function __construct($user, $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array(
|
||||
@@ -85,7 +87,9 @@ namespace Api\Mail {
|
||||
'subject' => new StringType('subject', -1),
|
||||
'body' => new StringType('body', -1),
|
||||
'replyTo' => new Parameter('replyTo', Parameter::TYPE_EMAIL, true, null),
|
||||
'replyName' => new StringType('replyName', 32, true, "")
|
||||
'replyName' => new StringType('replyName', 32, true, ""),
|
||||
"gpgFingerprint" => new StringType("gpgFingerprint", 64, true, null),
|
||||
'async' => new Parameter("async", Parameter::TYPE_BOOLEAN, true, true)
|
||||
));
|
||||
$this->isPublic = false;
|
||||
}
|
||||
@@ -101,11 +105,24 @@ namespace Api\Mail {
|
||||
}
|
||||
|
||||
$fromMail = $mailConfig->getProperty('from');
|
||||
$mailFooter = $mailConfig->getProperty('mail_footer');
|
||||
$toMail = $this->getParam('to') ?? $fromMail;
|
||||
$subject = $this->getParam('subject');
|
||||
$replyTo = $this->getParam('replyTo');
|
||||
$replyName = $this->getParam('replyName');
|
||||
$body = $this->getParam('body');
|
||||
$gpgFingerprint = $this->getParam("gpgFingerprint");
|
||||
|
||||
if ($this->getParam("async")) {
|
||||
$sql = $this->user->getSQL();
|
||||
$this->success = $sql->insert("MailQueue", ["from", "to", "subject", "body",
|
||||
"replyTo", "replyName", "gpgFingerprint"])
|
||||
->addRow($fromMail, $toMail, $subject, $body, $replyTo, $replyName, $gpgFingerprint)
|
||||
->execute() !== false;
|
||||
$this->lastError = $sql->getLastError();
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
|
||||
if (stripos($body, "<body") === false) {
|
||||
$body = "<body>$body</body>";
|
||||
@@ -114,6 +131,14 @@ namespace Api\Mail {
|
||||
$body = "<html>$body</html>";
|
||||
}
|
||||
|
||||
if (!empty($mailFooter)) {
|
||||
$email_signature = realpath(WEBROOT . DIRECTORY_SEPARATOR . $mailFooter);
|
||||
if (is_file($email_signature)) {
|
||||
$email_signature = file_get_contents($email_signature);
|
||||
$body .= $email_signature;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$mail = new PHPMailer;
|
||||
$mail->IsSMTP();
|
||||
@@ -129,12 +154,36 @@ namespace Api\Mail {
|
||||
$mail->Host = $mailConfig->getHost();
|
||||
$mail->Port = $mailConfig->getPort();
|
||||
$mail->SMTPAuth = true;
|
||||
$mail->Timeout = 15;
|
||||
$mail->Username = $mailConfig->getLogin();
|
||||
$mail->Password = $mailConfig->getPassword();
|
||||
$mail->SMTPSecure = 'tls';
|
||||
$mail->CharSet = 'UTF-8';
|
||||
$mail->msgHTML($body);
|
||||
$mail->AltBody = strip_tags($body);
|
||||
|
||||
if ($gpgFingerprint) {
|
||||
$encryptedHeaders = implode("\r\n", [
|
||||
"Date: " . (new \DateTime())->format(DateTimeInterface::RFC2822),
|
||||
"Content-Type: text/html",
|
||||
"Content-Transfer-Encoding: quoted-printable"
|
||||
]);
|
||||
|
||||
$mimeBody = $encryptedHeaders . "\r\n\r\n" . quoted_printable_encode($body);
|
||||
$res = GpgKey::encrypt($mimeBody, $gpgFingerprint);
|
||||
if ($res["success"]) {
|
||||
$encryptedBody = $res["data"];
|
||||
$mail->AltBody = '';
|
||||
$mail->Body = '';
|
||||
$mail->AllowEmpty = true;
|
||||
$mail->ContentType = PHPMailer::CONTENT_TYPE_MULTIPART_ENCRYPTED;
|
||||
$mail->addStringAttachment("Version: 1", null, PHPMailer::ENCODING_BASE64, "application/pgp-encrypted", "");
|
||||
$mail->addStringAttachment($encryptedBody, "encrypted.asc", PHPMailer::ENCODING_7BIT, "application/octet-stream", "");
|
||||
} else {
|
||||
return $this->createError($res["error"]);
|
||||
}
|
||||
} else {
|
||||
$mail->msgHTML($body);
|
||||
$mail->AltBody = strip_tags($body);
|
||||
}
|
||||
|
||||
$this->success = @$mail->Send();
|
||||
if (!$this->success) {
|
||||
@@ -415,4 +464,101 @@ namespace Api\Mail {
|
||||
return $this->success;
|
||||
}
|
||||
}
|
||||
|
||||
class SendQueue extends MailAPI {
|
||||
public function __construct(User $user, bool $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, [
|
||||
"debug" => new Parameter("debug", Parameter::TYPE_BOOLEAN, true, false)
|
||||
]);
|
||||
$this->isPublic = false;
|
||||
}
|
||||
|
||||
public function execute($values = array()): bool {
|
||||
if (!parent::execute($values)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$debug = $this->getParam("debug");
|
||||
$startTime = time();
|
||||
if ($debug) {
|
||||
echo "Start of processing mail queue at $startTime" . PHP_EOL;
|
||||
}
|
||||
|
||||
$sql = $this->user->getSQL();
|
||||
$res = $sql->select("uid", "from", "to", "subject", "body",
|
||||
"replyTo", "replyName", "gpgFingerprint", "retryCount")
|
||||
->from("MailQueue")
|
||||
->where(new Compare("retryCount", 0, ">"))
|
||||
->where(new Compare("status", "waiting"))
|
||||
->where(new Compare("nextTry", $sql->now(), "<="))
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== false);
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if ($this->success && is_array($res)) {
|
||||
if ($debug) {
|
||||
echo "Found " . count($res) . " mails to send" . PHP_EOL;
|
||||
}
|
||||
|
||||
$successfulMails = [];
|
||||
foreach ($res as $row) {
|
||||
|
||||
if (time() - $startTime >= 45) {
|
||||
$this->lastError = "Not able to process whole mail queue within 45 seconds, will continue on next time";
|
||||
break;
|
||||
}
|
||||
|
||||
$to = $row["to"];
|
||||
$subject = $row["subject"];
|
||||
|
||||
if ($debug) {
|
||||
echo "Sending subject=$subject to=$to" . PHP_EOL;
|
||||
}
|
||||
|
||||
$mailId = intval($row["uid"]);
|
||||
$retryCount = intval($row["retryCount"]);
|
||||
$req = new Send($this->user);
|
||||
$args = [
|
||||
"to" => $to,
|
||||
"subject" => $subject,
|
||||
"body" => $row["body"],
|
||||
"replyTo" => $row["replyTo"],
|
||||
"replyName" => $row["replyName"],
|
||||
"gpgFingerprint" => $row["gpgFingerprint"],
|
||||
"async" => false
|
||||
];
|
||||
$success = $req->execute($args);
|
||||
$error = $req->getLastError();
|
||||
|
||||
if (!$success) {
|
||||
$delay = [0, 720, 360, 60, 30, 1];
|
||||
$minutes = $delay[max(0, min(count($delay) - 1, $retryCount))];
|
||||
$nextTry = (new \DateTime())->modify("+$minutes minute");
|
||||
$sql->update("MailQueue")
|
||||
->set("retryCount", $retryCount - 1)
|
||||
->set("status", "error")
|
||||
->set("errorMessage", $error)
|
||||
->set("nextTry", $nextTry)
|
||||
->where(new Compare("uid", $mailId))
|
||||
->execute();
|
||||
} else {
|
||||
$successfulMails[] = $mailId;
|
||||
}
|
||||
}
|
||||
|
||||
$this->success = count($successfulMails) === count($res);
|
||||
if (!empty($successfulMails)) {
|
||||
$res = $sql->update("MailQueue")
|
||||
->set("status", "success")
|
||||
->where(new CondIn(new Column("uid"), $successfulMails))
|
||||
->execute();
|
||||
$this->success = $res !== false;
|
||||
$this->lastError = $sql->getLastError();
|
||||
}
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user