150 lines
5.0 KiB
PHP
150 lines
5.0 KiB
PHP
<?php
|
|
|
|
namespace com\fwdekker\deathnotifier\mailer;
|
|
|
|
use com\fwdekker\deathnotifier\Response;
|
|
use Exception;
|
|
use Monolog\Logger;
|
|
use PDO;
|
|
use PHPMailer\PHPMailer\Exception as MailerException;
|
|
use PHPMailer\PHPMailer\PHPMailer;
|
|
use PHPMailer\PHPMailer\SMTP;
|
|
|
|
|
|
/**
|
|
* Queues up mails and sends them when appropriate.
|
|
*/
|
|
class Mailer
|
|
{
|
|
/**
|
|
* @var Logger The logger to use for logging.
|
|
*/
|
|
private Logger $logger;
|
|
/**
|
|
* @var array<string, array<string, mixed>> The configuration to use for mailing.
|
|
*/
|
|
private array $config;
|
|
/**
|
|
* @var PDO The database connection to interact with.
|
|
*/
|
|
private PDO $conn;
|
|
|
|
|
|
/**
|
|
* Constructs a new mailer.
|
|
*
|
|
* @param array<string, array<string, mixed>> $config the configuration to use for mailing
|
|
* @param Logger $logger the logger to use for logging
|
|
* @param PDO $conn the connection to the email database
|
|
*/
|
|
public function __construct(array $config, Logger $logger, PDO $conn)
|
|
{
|
|
$this->logger = $logger;
|
|
$this->config = $config;
|
|
$this->conn = $conn;
|
|
}
|
|
|
|
|
|
/**
|
|
* Populates the database with the necessary structures for emails.
|
|
*
|
|
* @return void
|
|
*/
|
|
public function install(): void
|
|
{
|
|
$this->conn->exec("CREATE TABLE email_tasks(type TEXT NOT NULL,
|
|
recipient TEXT NOT NULL,
|
|
arg1 TEXT NOT NULL DEFAULT(''),
|
|
arg2 TEXT NOT NULL DEFAULT(''),
|
|
PRIMARY KEY (type, recipient, arg1, arg2));");
|
|
}
|
|
|
|
|
|
/**
|
|
* Queues an email to be sent.
|
|
*
|
|
* @param Email $email the email to queue
|
|
* @return Response a satisfied `Response` if the email was queued, or an unsatisfied `Response` otherwise
|
|
*/
|
|
public function queue_email(Email $email): Response
|
|
{
|
|
$stmt = $this->conn->prepare("INSERT OR IGNORE INTO email_tasks (type, recipient, arg1, arg2)
|
|
VALUES (:type, :recipient, :arg1, :arg2);");
|
|
$stmt->bindValue(":type", $email->type);
|
|
$stmt->bindValue(":recipient", $email->recipient);
|
|
$stmt->bindValue(":arg1", $email->arg1);
|
|
$stmt->bindValue(":arg2", $email->arg2);
|
|
|
|
return $stmt->execute() ? Response::satisfied() : Response::unsatisfied(null);
|
|
}
|
|
|
|
/**
|
|
* Sends all emails in the queue.
|
|
*
|
|
* @return void
|
|
*/
|
|
public function process_queue(): void
|
|
{
|
|
// Open mailer
|
|
$mailer = new PHPMailer();
|
|
$mailer->IsSMTP();
|
|
$mailer->CharSet = "UTF-8";
|
|
|
|
$mailer->SMTPAuth = true;
|
|
$mailer->SMTPDebug = SMTP::DEBUG_OFF;
|
|
$mailer->SMTPKeepAlive = true;
|
|
$mailer->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS;
|
|
$mailer->Host = $this->config["mail"]["host"];
|
|
$mailer->Port = $this->config["mail"]["port"];
|
|
$mailer->Username = $this->config["mail"]["username"];
|
|
$mailer->Password = $this->config["mail"]["password"];
|
|
try {
|
|
$mailer->setFrom($this->config["mail"]["username"], $this->config["mail"]["from_name"]);
|
|
} catch (MailerException $exception) {
|
|
$this->logger->error("Failed to set 'from' address while processing queue.", ["cause" => $exception]);
|
|
$mailer->smtpClose();
|
|
}
|
|
|
|
// Get queue
|
|
$stmt = $this->conn->prepare("SELECT type, recipient, arg1, arg2 FROM email_tasks;");
|
|
$stmt->execute();
|
|
$email_tasks = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
// Process queue
|
|
$stmt = $this->conn->prepare("DELETE FROM email_tasks
|
|
WHERE type=:type AND recipient=:recipient AND arg1=:arg1 AND arg2=:arg2;");
|
|
$stmt->bindParam(":type", $type);
|
|
$stmt->bindParam(":recipient", $recipient);
|
|
$stmt->bindParam(":arg1", $arg1);
|
|
$stmt->bindParam(":arg2", $arg2);
|
|
foreach ($email_tasks as ["type" => $type, "recipient" => $recipient, "arg1" => $arg1, "arg2" => $arg2]) {
|
|
try {
|
|
$email = Email::deserialize($type, $recipient, $arg1, $arg2);
|
|
$mailer->Subject = $email->getSubject();
|
|
$mailer->Body = $email->getBody($this->config);
|
|
|
|
try {
|
|
$mailer->addAddress($recipient);
|
|
$mailer->send();
|
|
} catch (MailerException $exception) {
|
|
$this->logger->error(
|
|
"Failed to send mail.",
|
|
["cause" => $exception, "email" => $email]
|
|
);
|
|
$mailer->getSMTPInstance()->reset();
|
|
}
|
|
|
|
$mailer->clearAddresses();
|
|
} catch (Exception $exception) {
|
|
$this->logger->error(
|
|
"Failed to send mail.",
|
|
["cause" => $exception]
|
|
);
|
|
$mailer->getSMTPInstance()->reset();
|
|
}
|
|
|
|
$stmt->execute();
|
|
}
|
|
}
|
|
}
|