7 * @link https://www.open-emr.org
8 * @author Brady Miller <brady.g.miller@gmail.com>
9 * @copyright Copyright (c) 2010 Open Support LLC
10 * @copyright Copyright (c) 2018 Brady Miller <brady.g.miller@gmail.com>
11 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
14 use OpenEMR\Common\Crypto\CryptoGen
;
15 use PHPMailer\PHPMailer\PHPMailer
;
16 use OpenEMR\Common\Twig\TwigContainer
;
17 use OpenEMR\Common\Logging\SystemLogger
;
18 use OpenEMR\Common\Database\QueryUtils
;
20 class MyMailer
extends PHPMailer
30 function __construct($throwExceptions = false)
32 // make sure we initiate our constructor here...
33 parent
::__construct($throwExceptions);
39 * Checks if the MyMailer service is configured for mail with all of the host parameters defined
42 public static function isConfigured()
44 switch ($GLOBALS['EMAIL_METHOD']) {
46 $requiredKeys = ['SMTP_HOST', 'SMTP_PORT', 'SMTP_SECURE'];
47 if ($GLOBALS['SMTP_Auth']) {
48 $requiredKeys[] = 'SMTP_USER';
49 $requiredKeys[] = 'SMTP_PASS';
57 foreach ($requiredKeys as $key) {
58 if (empty($GLOBALS[$key])) {
66 * Adds an email to the email queue
67 * @param string $sender
68 * @param string $recipient
69 * @param string $template
70 * @param array $templateData
73 public static function emailServiceQueueTemplatedEmail(string $sender, string $recipient, string $subject, string $template, array $templateData)
75 if (empty($sender) ||
empty($recipient) ||
empty($subject) ||
empty($template) ||
empty($templateData)) {
79 $body = json_encode($templateData);
80 QueryUtils
::sqlInsert("INSERT into `email_queue` (`sender`, `recipient`, `subject`, `body`, `template_name`, `datetime_queued`) VALUES (?, ?, ?, ?, ?, NOW())", [$sender, $recipient, $subject, $body, $template]);
82 } catch (\Exception
$e) {
83 (new SystemLogger())->errorLogCaller("Failed to add email to queue notification error " . $e->getMessage(), ['trace' => $e->getTraceAsString()]);
89 public static function emailServiceQueue(string $sender, string $recipient, string $subject, string $body): bool
91 if (empty($sender) ||
empty($recipient) ||
empty($subject) ||
empty($body)) {
95 sqlInsert("INSERT into `email_queue` (`sender`, `recipient`, `subject`, `body`, `datetime_queued`) VALUES (?, ?, ?, ?, NOW())", [$sender, $recipient, $subject, $body]);
99 public static function emailServiceRun(): void
102 // TODO: @adunsulag is there a reason we don't use a transaction here to prevent race conditions?
103 $res = sqlStatement("SELECT `id`, `sender`, `recipient`, `subject`, `body`, `template_name` FROM `email_queue` WHERE `sent` = 0");
105 // send emails in the queue (to avoid race conditions, sent flag is rechecked before sending the email and then quickly set before proceeding to send the email)
106 // (first ensure the email method is properly configured)
107 $emailMethodConfigured = self
::isConfigured();
108 while ($ret = sqlFetchArray($res)) {
109 $sql = sqlQuery("SELECT `sent` FROM `email_queue` WHERE `id` = ?", [$ret['id']]);
110 if ($sql['sent'] == 1) {
113 // Not sent, so set the sent flag, and then send the email
114 sqlStatement("UPDATE `email_queue` SET `sent` = 1, `datetime_sent` = NOW() WHERE `id` = ?", [$ret['id']]);
116 if ($emailMethodConfigured) {
118 $twigContainer = new TwigContainer(null, $GLOBALS['kernel']);
119 $twig = $twigContainer->getTwig();
120 if (!empty($ret['template_name'])) {
121 $templateData = json_decode($ret['body'], true);
122 // we make sure to prefix this so that people have to work inside the openemr namespace for email templates
123 $htmlBody = $twig->render($ret['template_name'] . ".html.twig", $templateData);
124 $textBody = $twig->render($ret['template_name'] . ".text.twig", $templateData);
126 $htmlBody = $twig->render("emails/system/system-notification.html.twig", ['message' => $ret['body']]);
127 $textBody = $twig->render("emails/system/system-notification.text.twig", ['message' => $ret['body']]);
130 $mail = new MyMailer();
131 $email_subject = $ret['subject'];
132 $email_sender = $ret['sender'];
133 $email_address = $ret['recipient'];
134 $mail->AddReplyTo($email_sender, $email_sender);
135 $mail->SetFrom($email_sender, $email_sender);
136 $mail->AddAddress($email_address);
137 $mail->Subject
= $email_subject;
138 $mail->MsgHTML($htmlBody);
139 $mail->AltBody
= $textBody;
141 if (!$mail->Send()) {
142 sqlStatement("UPDATE `email_queue` SET `error` = 1, `error_message`= ?, , `datetime_error` = NOW() WHERE `id` = ?", [$mail->ErrorInfo
, $ret['id']]);
143 error_log("Failed to send email notification through Mymailer emailServiceRun with error " . errorLogEscape($mail->ErrorInfo
));
145 } catch (\Exception
$e) {
146 (new SystemLogger())->errorLogCaller("Failed to generate email contents for queued email" . $e->getMessage(), ['trace' => $e->getTraceAsString(), 'id' => $ret['id']]);
147 sqlStatement("UPDATE `email_queue` SET `error` = 1, `error_message`= ?, `datetime_error` = NOW() WHERE `id` = ?", [$e->getMessage(), $ret['id']]);
150 sqlStatement("UPDATE `email_queue` SET `error` = 1, `error_message`= 'email method is not configured correctly', `datetime_error` = NOW() WHERE `id` = ?", [$ret['id']]);
151 error_log("Failed to send email notification through Mymailer since email method is not configured correctly");
157 function emailMethod()
159 global $HTML_CHARSET;
160 $this->CharSet
= $HTML_CHARSET;
161 switch ($GLOBALS['EMAIL_METHOD']) {
163 $this->Mailer
= "mail";
166 $this->Mailer
= "smtp";
167 $this->SMTPAuth
= $GLOBALS['SMTP_Auth'];
168 $this->Host
= $GLOBALS['SMTP_HOST'];
169 $this->Username
= $GLOBALS['SMTP_USER'];
170 $cryptoGen = new CryptoGen();
171 $this->Password
= $cryptoGen->decryptStandard($GLOBALS['SMTP_PASS']);
172 $this->Port
= $GLOBALS['SMTP_PORT'];
173 $this->SMTPSecure
= $GLOBALS['SMTP_SECURE'];
176 $this->Mailer
= "sendmail";