praiadeseselle/site/modules/WireMailSmtp/WireMailSmtp.module

1031 lines
39 KiB
Text
Raw Permalink Normal View History

2023-03-10 19:44:38 +01:00
<?php
/**
* SMTP Mailer WireMail module
*
* This module extends the WireMail base class and integrate the EmailMessage- and the SMTP-Library
* from M. Lemos (http://www.phpclasses.org/browse/author/1.html) into ProcessWire.
*
*
* @copyright Copyright (c) 2014 - 2023, Horst Nogajski
2023-03-10 19:44:38 +01:00
* @license http://www.gnu.org/licenses/gpl-2.0.txt GNU General Public License, version 2
* OR
* @license https://processwire.com/about/license/mit/
*
* ProcessWire 2.x & 3.x, Copyright 2020 by Ryan Cramer
* https://processwire.com
* https://processwire.com/about/license/mit/
*
**/
class WireMailSmtp extends WireMail implements Module, ConfigurableModule {
public static function getModuleInfo() {
return array(
'title' => 'Wire Mail SMTP',
'version' => '0.6.4',
2023-03-10 19:44:38 +01:00
'summary' => "Extends WireMail, uses SMTP protocol (plain | SSL | TLS), provides: to, cc, bcc, attachments, priority, disposition notification, bulksending, ...",
'href' => 'https://processwire.com/talk/topic/5704-module-wiremailsmtp/',
'author' => 'horst',
'singular' => false,
'autoload' => false
);
}
public static function getCryptoMethodsTLS() {
$validTlsCryptoMethods = array();
foreach(array(
'STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT', // since PHP 5.6.0
'STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT', // since PHP 5.6.0
'STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT', // since PHP 5.6.0
'STREAM_CRYPTO_METHOD_ANY_CLIENT', // since PHP 5.6.0
'STREAM_CRYPTO_METHOD_TLS_CLIENT', // BEFORE PHP 5.6.0
) as $item) {
if(defined($item) && constant($item)) $validTlsCryptoMethods[] = $item;
}
$a = array();
foreach($validTlsCryptoMethods as $value) $a[$value] = $value;
return $a;
}
public static function getCryptoMethodsSSL() {
return array();
}
/**
* Name of activity/error log files without extension (.txt)
*
*/
const LOG_FILENAME_ACTIVITY = 'wiremailsmtp_activity';
const LOG_FILENAME_ERROR = 'wiremailsmtp_errors';
const LOG_FILENAME_SENTLOG = 'wiremailsmtp_sentlog';
private $smtp = null;
private $maildata = array();
/**
* Mail properties
*
*/
protected $mail = array(
'to' => array(), // to addresses - associative: both key and value are email (to prevent dups)
'toName' => array(), // to names - associative: indexed by 'to' email address, may be blank/null for any email
'cc' => array(),
'ccName' => array(),
'bcc' => array(),
'from' => '',
'fromName' => '',
'priority' => '',
'dispositionNotification' => '',
'subject' => '',
'body' => '',
'bodyHTML' => '',
'addSignature' => null,
'attachments' => array(),
'header' => array(),
'sendSingle' => false,
'sendBulk' => false,
'useSentLog' => false,
'wrapText' => false
);
/**
* Default settings used by this module
*
* @return array
*/
static public function getDefaultData() {
return array(
'default_charset' => 'UTF-8',
'localhost' => '', // this computer address
'smtp_host' => '', // SMTP server address
'smtp_port' => 25, // SMTP server port
'smtp_ssl' => 0, // SMTP use SSL ?
'smtp_ssl_crypto_method' => '', // crypto method to use with SSL connections
'smtp_start_tls' => 0, // SMTP use START_TLS ?
'smtp_tls_crypto_method' => '', // crypto method to use with TLS connections
'smtp_user' => '', // SMTP user name
'smtp_password' => '', // SMTP password
'smtp_password2' => '', // SMTP password
'clear_smtp_password' => '', // SMTP password
'allow_without_authentication' => 0, // No user name and password required
'realm' => '', // Authentication realm or domain
'workstation' => '', // Workstation for NTLM authentication
'authentication_mechanism' => '', // SASL authentication mechanism
'smtp_debug' => 0, // debug smtp server communication?
'smtp_html_debug' => 0, // debug smtp server communication in HTML?
'sender_name' => '', // From: the senders name
'sender_email' => '', // From: the senders email address
'sender_reply' => '', // Reply-To: optional email address
'sender_errors_to' => '', // Errors-To: optional email address
'sender_signature' => '', // a Signature Text, like Contact Data and / or Confidentiality Notices
'sender_signature_html' => '', // a Signature Text in HTML, like Contact Data and / or Confidentiality Notices
'send_sender_signature' => '1', // when the signature should be send: with every mail | only when the default Email is the sender | only when explicitly called via the API
'extra_headers' => '', // optional Custom-Meta-Headers
'valid_recipients' => '', // email addresses of valid recipients. String that we convert to array at runtime.
'smtp_certificate' => 0 // allow or not self signed certificate (PHP >= 5.6)
2023-03-10 19:44:38 +01:00
);
}
/**
* This method is intended for usage with e.g. Newsletter-Modules.
* You can hook into it if you want use alternative stores for it
*
* This resets the Log for sent emaildresses. It starts a new Session.
* Best usage should be interactively when setting up a new Newsletter.
*
*
* @return boolean true if Log is empty or false if it is not empty
*
*/
public function ___sentLogReset() {
$filename = wire('config')->paths->logs . self::LOG_FILENAME_SENTLOG . '.txt';
@touch($filename);
$res = file_put_contents($filename, '', LOCK_EX );
if(false===$res || 0!==$res || !file_exists($filename) || !is_readable($filename) || !is_writeable($filename)) {
$this->logError('Cannot reset Content of the SentLog: ' . $filename);
throw new WireException('You want to make usage of the SentLog-feature, but cannot reset Content of the SentLog: ' . basename($filename));
}
return 0===$res ? true : false;
}
/**
* This method is intended for usage with e.g. Newsletter-Modules.
* You can hook into it if you want use alternative stores for it
*
* This returns an array containing all emailaddresses
*
*
* @return array with emailaddresses as values
*
*/
public function ___sentLogGet() {
$filename = wire('config')->paths->logs . self::LOG_FILENAME_SENTLOG . '.txt';
@touch($filename);
if(!file_exists($filename) || !is_readable($filename) || !is_writeable($filename)) {
$this->logError('Cannot get content of the SentLog: ' . $filename);
throw new WireException('You want to make usage of the SentLog-feature, but cannot get content of the SentLog: ' . basename($filename));
}
$a = explode("\n", trim(file_get_contents($filename)));
$emailaddresses = array();
foreach($a as $e) {
if(trim($e)=='') continue;
$emailaddresses[] = trim($e);
}
return $emailaddresses;
}
/**
* This method is intended for usage with e.g. Newsletter-Modules.
* You can hook into it if you want use alternative stores for it
*
* Add a emailaddress to the SentLog
* If you have enabled the usage it is called automatically within
* the send() loop to store each successful sent emailaddress.
*
*
* @param string Must be a single email address
* @return boolean true or false
*
*/
public function ___sentLogAdd($emailaddress) {
$filename = wire('config')->paths->logs . self::LOG_FILENAME_SENTLOG . '.txt';
$data = trim(str_replace(array('<','>'), '', $emailaddress)) . "\n";
$res = file_put_contents($filename, $data, LOCK_EX + FILE_APPEND );
if(false===$res || strlen($data)!=$res) {
$this->logError('Cannot add emailaddress to the SentLog: ' . $filename);
throw new WireException('You want to make usage of the SentLog-feature, but cannot add emailaddress to the SentLog: ' . basename($filename));
}
return strlen($data) === $res ? true : false;
}
/**
* This method is intended for usage with e.g. Newsletter-Modules.
*
* If the send() method should make usage of the SentLog set it to true!
*
*
* @param boolean true or false
* @return $this
*
*/
public function useSentLog($useIt=true) {
$this->mail['useSentLog'] = (bool)$useIt;
return $this;
}
/**
* Bundle module settings back into an array for WireMailSmtpAdaptor
*
*/
public function getSettings() {
$siteconfig = is_array($this->wire('config')->wiremailsmtp) ? $this->wire('config')->wiremailsmtp : array();
$settings = array();
foreach(self::getDefaultData() as $key => $value) {
$k = $key;
$v = $this->$key;
if($key === 'valid_recipients') {
// convert multi-line textarea value to array of emails
$emails = array();
foreach(explode("\n", $this->valid_recipients) as $email) {
if(trim($email)=='') continue;
$emails[] = trim($email);
}
$settings[$key] = $emails;
// now check for settings in site/config.php that should override the default settings from the module config:
if(isset($siteconfig[$key])) $settings[$key] = $siteconfig[$key];
continue;
}
if($key === 'extra_headers') {
// convert multi-line textarea value to array of Key => Value pairs
$extraHeaders = array();
foreach(explode("\n", $this->get('extra_headers')) as $extraHeader) {
if(trim($extraHeader)=='') continue;
$tmp = explode('=', $extraHeader);
if(!is_array($tmp) || count($tmp)!=2) continue;
$extraHeaders[$tmp[0]] = $tmp[1];
}
$settings[$key] = $extraHeaders;
// now check for settings in site/config.php that should override the default settings from the module config:
if(isset($siteconfig[$key])) $settings[$key] = $siteconfig[$key];
continue;
}
$settings[$k] = $this->$key;
// now check for settings in site/config.php that should override the default settings from the module config:
if(isset($siteconfig[$k])) $settings[$k] = $siteconfig[$k];
}
return $settings;
}
/**
* Populate default settings
*
*/
public function __construct() {
$this->mail['header']['X-Mailer'] = "ProcessWire/" . $this->className();
foreach(self::getDefaultData() as $key => $value) {
$this->$key = $value;
}
}
/**
* Initialize the module and setup hooks
*
*/
public function init() {
require_once(wire('config')->paths->WireMailSmtp . 'WireMailSmtpAdaptor.php');
$this->smtp = new hnsmtp($this->getSettings());
}
// public function ready() {
// }
public function __destruct() {
if($this->smtp) $this->smtp->close();
unset($this->smtp);
}
/**
* Save activity message to log file
*
*/
public function logActivity($message) {
$this->log->save( self::LOG_FILENAME_ACTIVITY , $message);
}
/**
* Save error message to log file
*
*/
public function logError($message) {
$this->log->save( self::LOG_FILENAME_ERROR , $message);
}
/**
* Build a form allowing configuration of this Module
*
*/
static public function getModuleConfigInputfields(array $data) {
$localhost = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : '');
$data = array_merge(self::getDefaultData(), array('localhost'=>$localhost), $data);
// // special handling for SMTP password
// // seen by @teppo's SwiftMailer
// if(isset($data['smtp_password2'])) {
// $data['smtp_password'] = $data['smtp_password2'];
// unset($data['smtp_password2'], $data['clear_smtp_password']);
// wire('modules')->saveModuleConfigData('WireMailSmtp', $data);
// }
// elseif(isset($data['clear_smtp_password']) && $data['clear_smtp_password']) {
// unset($data['smtp_password'], $data['smtp_password2'], $data['clear_smtp_password']);
// wire('modules')->saveModuleConfigData('WireMailSmtp', $data);
// }
// else {
// unset($data['smtp_password2'], $data['clear_smtp_password']);
// wire('modules')->saveModuleConfigData('WireMailSmtp', $data);
// }
require_once(dirname(__FILE__) . '/WireMailSmtpConfig.php');
$c = new WireMailSmtpConfig();
return $c->getConfig($data);
}
/**
* Return a ready-to-use copy of the Adaptor
*
*/
public function getAdaptor() {
return $this;
}
/**
* Set the email cc address
*
* Each added email addresses appends to any addresses already supplied, unless
* you specify NULL as the email address, in which case it clears them all.
*
* @param string|array|null $email Specify any ONE of the following:
* 1. Single email address or "User Name <user@example.com>" string.
* 2. CSV string of #1.
* 3. Non-associative array of #1.
* 4. Associative array of (email => name)
* 5. NULL (default value, to clear out any previously set values)
* @param string $name Optionally provide a FROM name, applicable
* only when specifying #1 (single email) for the first argument.
* @return this
* @throws WireException if any provided emails were invalid
*
*/
public function cc($email = null, $name = null) {
if(is_null($email)) {
// clear existing values
$this->mail['cc'] = array();
$this->mail['ccName'] = array();
return $this;
}
$emails = is_array($email) ? $email : explode(',', $email);
foreach($emails as $key => $value) {
$toName = '';
if(is_string($key)) {
// associative array
// email provided as $key, and $toName as value
$toEmail = $key;
$toName = $value;
} else if(strpos($value, '<') !== false && strpos($value, '>') !== false) {
// toName supplied as: "User Name <user@example.com"
list($toEmail, $toName) = $this->extractEmailAndName($value);
} else {
// just an email address, possibly with name as a function arg
$toEmail = $value;
}
if(empty($toName)) $toName = $name; // use function arg if not overwritten
$toEmail = $this->sanitizeEmail($toEmail);
$this->mail['cc'][$toEmail] = $toEmail;
$this->mail['ccName'][$toEmail] = $this->sanitizeHeader($toName);
}
return $this;
}
/**
* Set the email bcc address
*
* Each added email addresses appends to any addresses already supplied, unless
* you specify NULL as the email address, in which case it clears them all.
*
* @param string|array|null $email Specify any ONE of the following:
* 1. Single email address or "User Name <user@example.com>" string.
* 2. CSV string of #1.
* 3. Non-associative array of #1.
* 4. Associative array of (email => name)
* 5. NULL (default value, to clear out any previously set values)
* @param string $name Optionally provide a FROM name, applicable
* only when specifying #1 (single email) for the first argument.
* @return this
* @throws WireException if any provided emails were invalid
*
*/
public function bcc($email = null, $name = null) {
// a BCC Name isn't used, because BCC addresses by it's nature aren't kept in email messages
// we leave it here for compatibilty with TO and CC methods
if(is_null($email)) {
// clear existing values
$this->mail['bcc'] = array();
return $this;
}
$emails = is_array($email) ? $email : explode(',', $email);
foreach($emails as $key => $value) {
$toName = '';
if(is_string($key)) {
// associative array
// email provided as $key, and $toName as value
$toEmail = $key;
$toName = $value;
} else if(strpos($value, '<') !== false && strpos($value, '>') !== false) {
// toName supplied as: "User Name <user@example.com"
list($toEmail, $toName) = $this->extractEmailAndName($value);
} else {
// just an email address, possibly with name as a function arg
$toEmail = $value;
}
if(empty($toName)) $toName = $name; // use function arg if not overwritten
$toEmail = $this->sanitizeEmail($toEmail);
$this->mail['bcc'][$toEmail] = $toEmail;
}
return $this;
}
/**
* Set the 'cc' name
*
* It is preferable to do this with the cc() method, but this is provided to ensure that
* all properties can be set with direct access, i.e. $mailer->toName = 'User Name';
*
* This sets the 'to name' for whatever the last added 'cc' email address was.
*
* @param string
* @return this
* @throws WireException if you attempt to set a toName before a to email.
*
*/
public function ccName($name) {
$emails = $this->mail['cc'];
if(!count($emails)) throw new WireException("Please set a 'cc' address before setting a name.");
$email = end($emails);
$this->mail['ccName'][$email] = $this->sanitizeHeader($name);
return $this;
}
/**
* Set the email from address
*
* @param string Must be a single email address or "User Name <user@example.com>" string.
* @param string|null An optional FROM name (same as setting/calling fromName)
* @return this
* @throws WireException if provided email was invalid
*
*/
public function from($email = '', $name = null) {
if ($this->force_sender == 1){
$email = '';
}
elseif(is_null($name)) list($email, $name) = $this->extractEmailAndName($email);
2023-03-10 19:44:38 +01:00
if(empty($email)) {
$email = $this->sender_email;
$name = $this->sender_name;
}
if($name) $this->mail['fromName'] = $this->sanitizeHeader($name);
$this->mail['from'] = $email;
return $this;
}
/**
* Set the email priority headers
*
* @param number 1 | 2 | 3 | 4 | 5 ( 1 = highest | 3 = normal / default | 5 = lowest )
* @return this
*
*/
public function priority($number) {
$this->mail['priority'] = $number;
return $this;
}
/**
* Request a Disposition Notification
*
* @return this
*
*/
public function dispositionNotification($request=true) {
$this->mail['dispositionNotification'] = (bool)$request;
return $this;
}
public function notification($request=true) {
return $this->dispositionNotification($request);
}
// I don't find the param names of the core class to be intuitive or descriptive in the right way.
// The "$value" in real is the "filename" of the attachment, and the "$filename"
// in real is an "alternative BASENAME"! This may lead to confusion.
//
// But I have to use it the exact same way as in the core class, because otherwise the
// systems raises PHP strict notices about the different param names. :(
// So please, for better understanding, read on the example of the next method "attachments()".
//
// old code: public function attachment($filename, $alternativeBasename = '')
/**
* Add attachment to the email,
* (conform with the core Wiremail update introduced in PW 3.0.36)
*
* @param $filename string, Full path and filename of file attachment, (no URL!)
* @param $alternativeBasename (optional) string, Optional different basename for file as it appears in the mail
* @return WireMailSmtp
*/
public function attachment($value, $filename = '') {
$a = array($value => $filename);
return $this->attachments($a);
}
/**
* @param array $values, array with keys (absolute pathes to filenames) and optional values (alternative basenames)
* example: array(
* '/an/absolute/path/to/file.typ' => 'alternative-basename.typ',
* '/another/path/to/anotherfile.typ' => '',
* // ...
* )
* @return WireMailSmtp
*/
public function attachments($values) {
// $value is the fullpath filename (!), filename is an optional alternativeBasename (!), the terms are this way in PW core WireMail
foreach($values as $filename => $alternativeBasename) {
$this->mail['attachments'][trim($filename)] = trim($alternativeBasename);
}
return $this;
}
public function addSignature($add=true) {
$this->mail['addSignature'] = (bool)$add;
return $this;
}
public function wrapText($wrap=true) {
$this->mail['wrapText'] = (bool)$wrap;
return $this;
}
public function sendSingle($singleMail=true) {
$this->mail['sendSingle'] = (bool)$singleMail;
if((bool)$singleMail) {
$this->mail['sendBulk'] = false;
}
return $this;
}
public function single($singleMail=true) {
return $this->sendSingle($singleMail);
}
public function sendBulk($bulkMail=true) {
$this->mail['sendBulk'] = (bool)$bulkMail;
if((bool)$bulkMail) {
$this->mail['sendSingle'] = false;
}
return $this;
}
public function bulk($bulkMail=true) {
return $this->sendBulk($bulkMail);
}
public function ___send($debugServer = false) {
$this->smtp->setSender($this->mail['from'], $this->mail['fromName']);
if($this->mail['dispositionNotification']) $this->setNotification(); // must be called after setSender
$this->smtp->setCustomHeader($this->mail['header']);
if($this->mail['priority']!='') $this->setPriority($this->mail['priority']);
$this->setSubject($this->mail['subject']);
if($this->bodyHTML) {
// we use MultipartAlternative
$text = strlen($this->body) ? $this->body : strip_tags($this->bodyHTML);
$this->setTextAndHtmlBody($text, $this->bodyHTML, $this->mail['addSignature']);
} else {
// we use plaintext
$this->setTextBody($this->body, $this->mail['addSignature']);
}
foreach($this->mail['attachments'] as $value => $filename) {
$this->attachFile($value, $filename);
}
// check and optionally adjust setting for sendSingle
if($this->mail['sendSingle'] && count($this->to)>1) {
$this->mail['sendSingle'] = false;
$this->logError("You have set sendSingle to true, but also you have provided more than one TO-Recipient. We now change the sending method to send multiple messages!");
}
// send a single email and QUIT
2023-03-10 19:44:38 +01:00
if($this->mail['sendSingle']) {
// with sending only a single mail, we may also use cc and bcc recipients
// there should be only one TO recipients, but it is let to the user how he
// want handle this
foreach($this->to as $email) {
$name = $this->toName[$email];
$this->addRecipient($email, $name, 'to');
}
foreach($this->cc as $email) {
$name = $this->ccName[$email];
$this->addRecipient($email, $name, 'cc');
}
foreach($this->bcc as $email) {
$this->addRecipient($email, '', 'bcc');
}
// correct the recipient headers >>>
$tmpTO = $tmpCC = $tmpBCC = array();
2023-03-10 19:44:38 +01:00
foreach($this->maildata['recipients'] as $tmpRecipient) {
$tmpRecipientStr = strlen(trim($tmpRecipient['name'])) > 0 ? '"'. trim($tmpRecipient['name']) .'" ' : '';
$tmpRecipientStr .= '<'. trim($tmpRecipient['emailaddress']) .'>';
switch($tmpRecipient['type']) {
case 'to':
$tmpTO[$tmpRecipient['emailaddress']] = $tmpRecipientStr;
break;
case 'cc':
$tmpCC[$tmpRecipient['emailaddress']] = $tmpRecipientStr;
break;
case 'bcc':
$tmpBCC[$tmpRecipient['emailaddress']] = $tmpRecipientStr;
break;
}
}
$tmpTOstr = implode(', ', $tmpTO);
$tmpCCstr = implode(', ', $tmpCC);
$tmpBCCstr = implode(', ', $tmpBCC);
#$this->smtp->setHeader('To', trim($tmpTOstr));
if ($tmpCCstr) {
$this->smtp->setHeader('CC', trim($tmpCCstr));
}
if ($tmpBCCstr) {
$this->smtp->setHeader('BCC', trim($tmpBCCstr));
}
unset($tmpRecipient, $tmpRecipientStr, $tmpTO, $tmpTOstr, $tmpCC, $tmpCCstr, $tmpBCC, $tmpBCCstr);
// <<< correct the recipient headers
$maildata = '';
$ret = $this->smtp->send($debugServer, $debugServer, $maildata);
$this->maildata['send'] = $maildata;
return $ret ? 1 : 0;
}
// send multiple messages and quit
$numSent = 0;
$recipientsSuccess = array();
$recipientsFailed = array();
if($this->mail['useSentLog']) {
$sent = $this->sentLogGet();
if(!is_array($sent)) {
$this->logError('Cannot get content of the SentLog!');
throw new WireException('You want to make usage of the SentLog-feature, but cannot get content of the SentLog!');
}
$recipientsSuccess = $sent;
unset($sent);
}
if(count($this->to)>50) $this->mail['sendBulk'] = true;
if(count($this->to)>5 || $this->mail['sendBulk']) $this->smtp->SetBulkMail(1);
if($this->mail['sendBulk']) $this->smtp->SetHeader('Precedence', 'bulk');
foreach($this->bcc as $bcc) $this->addRecipient($bcc, '', 'bcc');
foreach($this->to as $to) {
if(in_array($to, $recipientsSuccess)) continue; // "Only one cross each" (Monty Python: The Life of Brian)
set_time_limit(intval(30));
$toName = $this->mail['toName'][$to];
$this->addRecipient($to, $toName, 'to');
$ret = $this->smtp->send($debugServer, $debugServer, $maildata);
if($ret) {
$recipientsSuccess[$to] = $to;
if($this->mail['useSentLog'] && ! $this->sentLogAdd($to)) {
$this->logError('Cannot add emailaddress to the SentLog: ' . SELF::LOG_FILENAME_SENTLOG . '.txt');
throw new WireException('You want to make usage of the SentLog-feature, but cannot add emailaddress to the SentLog: ' . SELF::LOG_FILENAME_SENTLOG . '.txt');
}
}
else {
$recipientsFailed[$to] = $to;
}
$numSent += $ret ? 1 : 0;
}
if(count($this->to)>5 || $this->mail['sendBulk']) $this->smtp->SetBulkMail(0);
$this->smtp->close();
if(!isset($maildata) && 0==$numSent) $maildata = 'no messages are sent';
$this->maildata['send'] = $maildata;
$this->maildata['recipientsSuccess'] = $recipientsSuccess;
$this->maildata['recipientsFailed'] = $recipientsFailed;
return $numSent;
}
/**
* This method is intended for verbose debug purposes!
* Use this instead of the regular send() method.
*
* @returns a debugDump in string format
* @param $outputMode: integer, 1 = echo HTML | 2 = echo PlainText | 3 return String | 4 = write into file
* @param $filename: string, path to writeable log filename, required for $outputMode = 4
*/
public function debugSend($outputMode = 1, $filename = '') {
ob_start();
$this->send(true);
$debugLog = "\n\n" . ob_get_clean();
ob_start();
$dump = '';
$dump .= $this->mvd(array('SETTINGS' => $this->getSettings()), $outputMode, $filename);
$dump .= $this->mvd(array('RESULT' => $this->getResult()), $outputMode, $filename);
$dump .= $this->mvd(array('ERRORS' => $this->getErrors()), $outputMode, $filename);
$dump .= $this->mvd(array('DEBUGLOG' => $debugLog), $outputMode, $filename);
$return = ob_get_clean();
if(1 == $outputMode || 2 == $outputMode) {
echo $return;
$dump = $return;
}
return str_replace(array($this->mvdWrap1(), $this->mvdWrap2(), "\n<!--", "\n-->"), '', $dump);
}
public function getResult() {
// Returns an array with all settings and content of the current email
return $this->maildata;
}
public function getErrors() {
// Returns an array of error messages, if they occurred.
// Returns blank array if no errors occurred.
// The module would call this after getImages() or testConnection() to
// see if it should display/log any error messages.
return (array)$this->smtp->getErrors();
}
public function testConnection() {
// Tests that the email settings work. This would be used by the module at
// config time to give the user a Yes or No as to whether their email settings
// are functional. Returns a boolean TRUE or FALSE.
return $this->smtp->testConnection();
}
// formatting for debug log output, used by debugSend()
private function mvd($v, $outputMode = 1, $filename = '') {
ob_start();
var_dump($v);
$content = ob_get_contents();
ob_end_clean();
$m = 0;
preg_match_all('#^(.*)=>#mU', $content, $stack);
$lines = $stack[1];
$indents = array_map('strlen', $lines);
if($indents) $m = max($indents) + 1;
$content = preg_replace_callback(
'#^(.*)=>\\n\s+(\S)#Um',
function($match) use ($m) {
return $match[1] . str_repeat(' ', ($m - strlen($match[1]) > 1 ? $m - strlen($match[1]) : 1)) . $match[2];
},
$content
);
$content = preg_replace('#^((\s*).*){$#m', "\\1\n\\2{", $content);
$content = str_replace(array('<pre>', '</pre>'), '', $content);
switch($outputMode) {
case 1:
// Output to Browser-Window
echo $this->mvdWrap1() . $content . $this->mvdWrap2();
break;
case 2:
// Output to Commandline-Window or to Browser as hidden comment
echo isset($_SERVER['HTTP_HOST']) ? "\n<!--\n{$content}\n-->\n" : "{$content}\n";
break;
case 3:
// Output into a StringVar
return $this->mvdWrap1() . $content . $this->mvdWrap2();
break;
case 4:
// Output into a file, if a valid filename is given and we have write access to it
@touch($filename);
if(is_writable($filename)) {
$content = str_replace(array('&gt;','&quot;','&#10;'), array('>','"',''), strip_tags($content));
$res = file_put_contents($filename, $content, FILE_APPEND);
wireChmod($filename);
return $res === strlen($content);
}
return false;
break;
}
}
private function mvdWrap1() { return "<pre style=\"overflow:scroll !important; margin: 10px 20px; padding: 10px 10px 10px 10px; background-color:#F2F2F2; color:#000; border: 1px solid #333; font-family:'Hack', 'Source Code Pro', 'Lucida Console', 'Courier', monospace; font-size:12px; line-height:15px;\">"; }
private function mvdWrap2() { return "</pre>"; }
/* $type = ['To'|'CC'|'BCC'] */
protected function addRecipient($emailaddress, $name='', $type='To') {
if(!in_array(strtoupper($type), array('TO','CC','BCC'))) {
$type = 'To';
}
$emailaddress = str_replace(array('<', '>'), '', $emailaddress);
$this->maildata['recipients'][] = array('emailaddress'=>$emailaddress, 'name'=>$name, 'type'=>$type);
return $this->smtp->setEmailHeader($type, $emailaddress, $name);
}
protected function setSubject($text) {
$this->maildata['subject'] = (string)$text;
return $this->smtp->setHeader('Subject', (string)$text);
}
protected function setTextBody($text, $addSignature=null) {
$maildata = '';
if(!is_bool($addSignature)) {
if(in_array($this->send_sender_signature, array('1','2','3'))) {
switch($this->send_sender_signature) {
case '1': // only when explicitly called via API
$addSignature = false;
break;
case '2': // automaticaly when FROM = Sender Emailaddress
$from = strtolower(trim(str_replace(array('<','>'), '', $this->from)));
$sender = strtolower(trim(str_replace(array('<','>'), '', $this->sender_email)));
$addSignature = $from == $sender || '' == $from ? true : false;
break;
case '3': // automaticaly with _every_ Message
$addSignature = true;
break;
}
}
else {
$addSignature = false;
}
}
$res = $this->smtp->setTextBody($text, $addSignature, $this->wrapText, $maildata);
$this->maildata['addSignature'] = $addSignature ? '1' : '0';
$this->maildata['textbody'] = $maildata;
return $res;
}
protected function setTextAndHtmlBody($text, $html, $addSignature=null) {
$maildata1 = $maildata2 = '';
if(!is_bool($addSignature)) {
if(in_array($this->send_sender_signature, array('1','2','3'))) {
switch($this->send_sender_signature) {
case '1': // only when explicitly called via API
$addSignature = false;
break;
case '2': // automaticaly when FROM = Sender Emailaddress
$from = strtolower(trim(str_replace(array('<','>'), '', $this->from)));
$sender = strtolower(trim(str_replace(array('<','>'), '', $this->sender_email)));
$addSignature = $from == $sender || '' == $from ? true : false;
break;
case '3': // automaticaly with _every_ Message
$addSignature = true;
break;
}
}
else {
$addSignature = false;
}
}
$res = $this->smtp->setTextAndHtmlBody($text, $html, $addSignature, $this->wrapText, $maildata1, $maildata2);
$this->maildata['addSignature'] = $addSignature ? '1' : '0';
$this->maildata['textbody'] = $maildata1;
$this->maildata['htmlbody'] = $maildata2;
return $res;
}
// updated to PW 3.0.36 new attachment function with optional alternative basename
protected function attachFile($value, $filename = '') {
if(!file_exists($value) || !is_readable($value)) {
$this->logError('Error in $WireMailSmtp->attachFile($filename): Not existing or not readable file: ' . $value);
return false;
}
$attachment = array(
'FileName' => $value,
'Content-Type' => 'automatic/name',
'Disposition' => 'attachment'
);
if($filename) $attachment['Name'] = $filename; // optional alternative basename
$ret = $this->smtp->addAttachment($attachment);
if(!$ret) {
return false;
}
$this->maildata['attachments'][] = $value; // logging attachment filename
return true;
}
protected function setNotification() {
$maildata = '';
$ret = $this->smtp->setNotification($maildata);
if($ret) {
$this->maildata['notification'] = $maildata;
}
return $ret;
}
/* $priority = [ 1 | 2 | (3) | 4 | 5 ] */
protected function setPriority($priority=3) {
if($ret = (bool)$this->smtp->setPriority($priority)) {
$this->maildata['priority'] = $priority;
}
return $ret;
}
/**
* Return instance of the installer class
*
*/
protected function getInstaller() {
#require_once(dirname(__FILE__) . '/WireMailSmtpInstall.php');
#return new WireMailSmtpInstall();
}
/**
* Perform installation
*
*/
public function ___install() {
#$this->getInstaller()->install(self::$defaultSettings);
}
/**
* Perform uninstall
*
*/
public function ___uninstall() {
#$this->getInstaller()->uninstall($this);
}
}