Files
thetool/application/Emailnotification/Emailnotification.php
2025-08-22 17:49:54 +02:00

230 lines
7.4 KiB
PHP

<?php
require_once("Mail.php");
require_once("Mail/mime.php");
class Emailnotification {
private $headers = [];
private $subject;
private $body;
private $html;
private $from_name = false;
private $email_from = false;
private $email_to = false;
private $attachments = [];
private $object_type = "";
private $object_id = 0;
private $object_data = "";
private $_mimeheaders;
public function __construct($object_type = false, $object_id = false, $object_data = false) {
$this->headers = [
'X-Mailer' => MFAPPNAME.' Mailer',
];
$this->email_from = TT_OUTGOING_EMAIL;
$this->from_name = TT_OUTGOING_EMAIL_NAME;
if($object_type !== false) $this->object_type = $object_type;
if($object_id !== false) $this->object_id = $object_id;
if($object_data !== false) $this->object_data = $object_data;
}
public function addAttachment($filepath = null, $content = null, $name = false, $c_type = "application/octet-stream", $disposition = "attachment", $encoding = "base64" , $charset = "utf-8") {
$attachment = [
"file" => $filepath,
"content" => $content,
"name" => $name,
"c_type" => $c_type,
"disposition" => $disposition,
"encoding" => $encoding,
"charset" => $charset
];
$attachment["isfile"] = false;
if($filepath) {
$attachment['isfile'] = true;
}
$this->attachments[] = $attachment;
}
public function setHeader($name, $value) {
$this->headers[$name] = $value;
}
public function setSubject($subject) {
$this->subject = $subject;
}
public function setBody($body) {
$this->body = $body;
}
public function setHtmlBody($html) {
$this->html = $html;
}
public function setFrom($email, $name = false) {
$this->email_from = $email;
$this->from_name = $name;
}
public function setTo($email) {
$this->email_to = $email;
}
public function send() {
if(!$this->email_to) {
return false;
}
if(!$this->body && !$this->html) {
return false;
}
if(!is_array($this->headers) || !count($this->headers)) {
return false;
}
if(!$this->subject) {
return false;
}
if(!array_key_exists("Subject", $this->headers) || !$this->headers['Subject']) {
$this->setHeader("Subject", $this->subject);
}
if((!array_key_exists("From", $this->headers) || !$this->headers['From']) && $this->from_name) {
$this->headers['From'] = '"'.$this->from_name.'" <'.$this->email_from.'>';
}
$log = mfLoghandler::singleton();
//var_dump($this);exit;
$mimeparams['text_encoding']="8bit";
$mimeparams['text_charset']="utf-8";
$mimeparams['html_charset']="utf-8";
$mimeparams['head_charset']="utf-8";
$mime = new Mail_mime();
if($this->body) {
$mime->setTXTBody($this->body);
}
if($this->html) {
$mime->setHTMLBody($this->html);
}
//var_dump($this->attachments);exit;
if(count($this->attachments)) {
foreach($this->attachments as $att) {
if($att['isfile']) {
$mime->addAttachment($att["file"], $att["c_type"], $att["name"], true, $att['encoding'], $att['disposition'], $att['charset']);
} else {
$mime->addAttachment($att["content"], $att["c_type"], $att["name"], false, $att['encoding'], $att['disposition'], $att['charset']);
}
}
}
$body = $mime->get($mimeparams);
$headers = $mime->headers($this->headers);
$this->_mimeheaders = $headers;
//$log->debug(print_r($headers, true));
$mail =& Mail::factory('mail', ["-f ".$this->email_from]);
/*
* PHP 8's mail() function now outputs proper line endings in headers (CRLF instead of LF).
* Mail_mail < 2.0 would detect a unix system and change the headers line ending to LF.
* On Mail submission to Exim (via sendmail), mail() adds its own headers first with CRLF line ending,
* making Exim treat every subsequent header's LF as an invalid line ending, adding a whitespace after the LF,
* making all our custom headers into one long header.
*
* See: https://www.exim.org/exim-html-current/doc/html/spec_html/ch-message_processing.html#SECTlineendings
*
* So we force CRLF line endings for headers here.
*/
$mail->sep = "\r\n";
$mail->send($this->email_to, $headers, $body);
$this->_createEmailLog();
return true;
}
private function _createEmailLog() {
if(!$this->object_id || !$this->object_type) return true;
$log = mfLoghandler::singleton();
if(array_key_exists("To", $this->_mimeheaders)) {
$this->_mimeheaders['To'] = $this->email_to;
}
FronkDB::singleton()->startTransaction();
$el = EmailLog::create([
'object_type' => $this->object_type,
'object_id' => $this->object_id,
'object_data' => $this->object_data,
'from' => $this->email_from,
'to' => $this->email_to,
'headers' => json_encode($this->_mimeheaders),
'subject' => $this->subject,
'body_text' => $this->body,
'body_html' => $this->html,
]);
if(!$el->save()) {
$log->error(__METHOD__.": Error saving EmailLog. {$this->object_type}: {$this->object_id} from: '{$this->email_from}' | to: '{$this->email_to}' | subject: '{$this->subject}'");
FronkDB::singleton()->rollbackTransaction();
return false;
}
if(is_array($this->attachments) && count($this->attachments)) {
foreach($this->attachments as $att) {
if($att['isfile']) {
if(!file_exists($att["file"])) {
$log->error(__METHOD__.": File not found. ".$this->object_type.": ".$this->object_id." / Filename: ".$att['name']);
continue;
}
$sha256_hash = hash_file("sha256", $att["file"]);
$filesize = filesize($att["file"]);
$file_content = file_get_contents($att["file"]);
} else {
$sha256_hash = hash("sha256", $att["content"]);
$filesize = strlen($att["content"]);
$file_content = $att["content"];
}
// find attachment content or create it
$ela_content = EmailLogAttachmentContent::getFirst(['sha256' => $sha256_hash]);
if(!$ela_content) {
$ela_content = EmailLogAttachmentContent::create([
'mimetype' => $att['c_type'],
'filesize' => $filesize,
'sha256' => $sha256_hash,
'content' => $file_content,
]);
if (!$ela_content->save()) {
$log->error(__METHOD__ . ": Error saving EmailLogAttachmentContent. " . $this->object_type . ": " . $this->object_id . " / Filename: " . $att['name']);
continue;
}
}
$ela = EmailLogAttachment::create([
'emaillog_id' => $el->id,
'content_id' => $ela_content->id,
'filename' => $att['name'],
]);
if(!$ela->save()) {
$log->error(__METHOD__.": Error saving EmailLogAttachment. ".$this->object_type.": ".$this->object_id." / Filename: ".$att['name']);
}
}
}
FronkDB::singleton()->commitTransaction();
}
}