2017-08-20 17:52:35 +00:00
|
|
|
<?php
|
2021-03-05 03:08:47 +00:00
|
|
|
/**
|
|
|
|
* @package Joomla.Component.Builder
|
|
|
|
*
|
|
|
|
* @created 30th April, 2015
|
|
|
|
* @author Llewellyn van der Merwe <http://www.joomlacomponentbuilder.com>
|
|
|
|
* @github Joomla Component Builder <https://github.com/vdm-io/Joomla-Component-Builder>
|
|
|
|
* @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.
|
|
|
|
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
2018-05-18 06:28:27 +00:00
|
|
|
*/
|
2017-08-20 17:52:35 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Componentbuilder component email helper
|
|
|
|
*/
|
|
|
|
abstract class ComponentbuilderEmail
|
|
|
|
{
|
2019-01-14 15:32:23 +00:00
|
|
|
/**
|
|
|
|
* The active recipient
|
|
|
|
*
|
|
|
|
* @var activeRecipient (array)
|
|
|
|
*/
|
|
|
|
public static $active = array();
|
|
|
|
|
2017-08-20 17:52:35 +00:00
|
|
|
/**
|
|
|
|
* Configuraiton object
|
|
|
|
*
|
|
|
|
* @var JConfig
|
|
|
|
*/
|
|
|
|
public static $config = null;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Mailer object
|
|
|
|
*
|
|
|
|
* @var JMail
|
|
|
|
*/
|
|
|
|
public static $mailer = null;
|
|
|
|
|
2018-06-21 14:25:49 +00:00
|
|
|
/**
|
|
|
|
* Custom Headers
|
|
|
|
*
|
|
|
|
* @var array
|
|
|
|
*/
|
|
|
|
protected static $header = array();
|
|
|
|
|
2017-08-20 17:52:35 +00:00
|
|
|
/**
|
|
|
|
* Get a configuration object
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
public static function getConfig()
|
|
|
|
{
|
|
|
|
if (!self::$config)
|
|
|
|
{
|
|
|
|
self::$config = JComponentHelper::getParams('com_componentbuilder');
|
|
|
|
}
|
|
|
|
|
|
|
|
return self::$config;
|
|
|
|
}
|
2018-06-21 14:25:49 +00:00
|
|
|
|
2019-01-14 15:32:23 +00:00
|
|
|
/**
|
|
|
|
* Returns the global mailer object, only creating it if it doesn't already exist.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
public static function getMailerInstance()
|
|
|
|
{
|
|
|
|
if (!self::$mailer)
|
|
|
|
{
|
|
|
|
self::$mailer = self::createMailer();
|
|
|
|
}
|
|
|
|
|
|
|
|
return self::$mailer;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check that a string looks like an email address.
|
|
|
|
* @param string $address The email address to check
|
|
|
|
* @param string|callable $patternselect A selector for the validation pattern to use :
|
|
|
|
* * `auto` Pick best pattern automatically;
|
|
|
|
* * `pcre8` Use the squiloople.com pattern, requires PCRE > 8.0, PHP >= 5.3.2, 5.2.14;
|
|
|
|
* * `pcre` Use old PCRE implementation;
|
|
|
|
* * `php` Use PHP built-in FILTER_VALIDATE_EMAIL;
|
|
|
|
* * `html5` Use the pattern given by the HTML5 spec for 'email' type form input elements.
|
|
|
|
* * `noregex` Don't use a regex: super fast, really dumb.
|
|
|
|
* Alternatively you may pass in a callable to inject your own validator, for example:
|
|
|
|
* PHPMailer::validateAddress('user@example.com', function($address) {
|
|
|
|
* return (strpos($address, '@') !== false);
|
|
|
|
* });
|
|
|
|
* You can also set the PHPMailer::$validator static to a callable, allowing built-in methods to use your validator.
|
|
|
|
* @return boolean
|
|
|
|
* @static
|
|
|
|
* @access public
|
|
|
|
*/
|
|
|
|
public static function validateAddress($address, $patternselect = null)
|
|
|
|
{
|
|
|
|
return self::getMailerInstance()->validateAddress($address, $patternselect);
|
|
|
|
}
|
|
|
|
|
2017-08-20 17:52:35 +00:00
|
|
|
/**
|
|
|
|
* Get a mailer object.
|
|
|
|
*
|
|
|
|
* Returns the global {@link JMail} object, only creating it if it doesn't already exist.
|
|
|
|
*
|
|
|
|
* @return JMail object
|
|
|
|
*
|
|
|
|
* @see JMail
|
|
|
|
*/
|
|
|
|
public static function getMailer()
|
|
|
|
{
|
|
|
|
if (!self::$mailer)
|
|
|
|
{
|
|
|
|
self::$mailer = self::createMailer();
|
|
|
|
}
|
|
|
|
|
|
|
|
$copy = clone self::$mailer;
|
|
|
|
|
|
|
|
return $copy;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create a mailer object
|
|
|
|
*
|
|
|
|
* @return JMail object
|
|
|
|
*
|
|
|
|
* @see JMail
|
|
|
|
*/
|
|
|
|
protected static function createMailer()
|
|
|
|
{
|
|
|
|
// set component params
|
|
|
|
$conf = self::getConfig();
|
|
|
|
|
|
|
|
// now load the mailer
|
|
|
|
$mailer = $conf->get('mailer', 'global');
|
|
|
|
|
|
|
|
// Create a JMail object
|
|
|
|
$mail = JMail::getInstance();
|
|
|
|
|
|
|
|
// check if set to global
|
|
|
|
if ('global' == $mailer)
|
|
|
|
{
|
|
|
|
// get the global details
|
|
|
|
$globalConf = JFactory::getConfig();
|
|
|
|
|
|
|
|
$mailer = $globalConf->get('mailer');
|
|
|
|
$smtpauth = ($globalConf->get('smtpauth') == 0) ? null : 1;
|
|
|
|
$smtpuser = $globalConf->get('smtpuser');
|
|
|
|
$smtppass = $globalConf->get('smtppass');
|
|
|
|
$smtphost = $globalConf->get('smtphost');
|
|
|
|
$smtpsecure = $globalConf->get('smtpsecure');
|
|
|
|
$smtpport = $globalConf->get('smtpport');
|
|
|
|
$sendmail = $globalConf->get('sendmail');
|
|
|
|
$mailfrom = $globalConf->get('mailfrom');
|
|
|
|
$fromname = $globalConf->get('fromname');
|
2017-08-20 20:47:14 +00:00
|
|
|
$replyto = $globalConf->get('replyto');
|
|
|
|
$replytoname = $globalConf->get('replytoname');
|
2017-08-20 17:52:35 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$smtpauth = ($conf->get('smtpauth') == 0) ? null : 1;
|
|
|
|
$smtpuser = $conf->get('smtpuser');
|
|
|
|
$smtppass = $conf->get('smtppass');
|
|
|
|
$smtphost = $conf->get('smtphost');
|
|
|
|
$smtpsecure = $conf->get('smtpsecure');
|
|
|
|
$smtpport = $conf->get('smtpport');
|
|
|
|
$sendmail = $conf->get('sendmail');
|
2018-05-17 01:02:11 +00:00
|
|
|
$mailfrom = $conf->get('emailfrom');
|
2017-08-20 17:52:35 +00:00
|
|
|
$fromname = $conf->get('fromname');
|
2017-08-20 20:47:14 +00:00
|
|
|
$replyto = $conf->get('replyto');
|
|
|
|
$replytoname = $conf->get('replytoname');
|
|
|
|
}
|
2018-07-30 06:10:50 +00:00
|
|
|
|
|
|
|
// Set global sender
|
|
|
|
$mail->setSender(array($mailfrom, $fromname));
|
2017-08-20 17:52:35 +00:00
|
|
|
|
2017-08-20 20:47:14 +00:00
|
|
|
// set the global reply-to if found
|
|
|
|
if ($replyto && $replytoname)
|
|
|
|
{
|
|
|
|
$mail->ClearReplyTos();
|
2018-07-30 06:10:50 +00:00
|
|
|
$mail->addReplyTo($replyto, $replytoname);
|
2017-08-20 17:52:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Default mailer is to use PHP's mail function
|
|
|
|
switch ($mailer)
|
|
|
|
{
|
|
|
|
case 'smtp':
|
|
|
|
// set the SMTP option
|
|
|
|
$mail->useSMTP($smtpauth, $smtphost, $smtpuser, $smtppass, $smtpsecure, $smtpport);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'sendmail':
|
|
|
|
// set the sendmail option
|
|
|
|
$mail->useSendmail($sendmail);
|
|
|
|
$mail->IsSendmail();
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
$mail->IsMail();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $mail;
|
|
|
|
}
|
|
|
|
|
2018-06-21 14:25:49 +00:00
|
|
|
/**
|
|
|
|
* Set a Mail custom header.
|
|
|
|
*
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public static function setHeader($target, $value)
|
|
|
|
{
|
|
|
|
// set the header
|
|
|
|
self::$header[$target] = $value;
|
|
|
|
}
|
|
|
|
|
2017-08-20 17:52:35 +00:00
|
|
|
/**
|
|
|
|
* Send an email
|
|
|
|
*
|
|
|
|
* @return bool on success
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
public static function send($recipient, $subject, $body, $textonly, $mode = 0, $bounce_email = null, $idsession = null, $mailreply = null, $replyname = null , $mailfrom = null, $fromname = null, $cc = null, $bcc = null, $attachment = null, $embeded = null , $embeds = null)
|
|
|
|
{
|
|
|
|
// Get a JMail instance
|
|
|
|
$mail = self::getMailer();
|
|
|
|
|
|
|
|
// set component params
|
|
|
|
$conf = self::getConfig();
|
|
|
|
|
|
|
|
// set if we have override
|
|
|
|
if ($mailfrom && $fromname)
|
|
|
|
{
|
|
|
|
$mail->setSender(array($mailfrom, $fromname));
|
|
|
|
}
|
|
|
|
|
|
|
|
// load the bounce email as sender if set
|
|
|
|
if (!is_null($bounce_email))
|
2017-12-15 01:10:10 +00:00
|
|
|
{
|
2017-08-20 17:52:35 +00:00
|
|
|
$mail->Sender = $bounce_email;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add tag to email to identify it
|
|
|
|
if (!is_null($idsession))
|
|
|
|
{
|
|
|
|
$mail->addCustomHeader('X-VDMmethodID:'.$idsession);
|
|
|
|
}
|
2018-06-21 14:25:49 +00:00
|
|
|
|
|
|
|
// set headers if found
|
|
|
|
if (isset(self::$header) && is_array(self::$header) && count((array)self::$header) > 0)
|
|
|
|
{
|
|
|
|
foreach (self::$header as $_target => $_value)
|
|
|
|
{
|
|
|
|
$mail->addCustomHeader($_target.':'.$_value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-20 17:52:35 +00:00
|
|
|
// set the subject & Body
|
|
|
|
$mail->setSubject($subject);
|
|
|
|
$mail->setBody($body);
|
|
|
|
|
|
|
|
// Are we sending the email as HTML?
|
|
|
|
if ($mode)
|
|
|
|
{
|
|
|
|
$mail->IsHTML(true);
|
|
|
|
$mail->AltBody = $textonly;
|
|
|
|
}
|
|
|
|
|
|
|
|
//embed images
|
|
|
|
if ($embeded)
|
|
|
|
{
|
|
|
|
if(ComponentbuilderHelper::checkArray($embeds))
|
|
|
|
{
|
|
|
|
foreach($embeds as $embed)
|
|
|
|
{
|
|
|
|
$mail->AddEmbeddedImage($embed->Path,$embed->FileName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$mail->addRecipient($recipient);
|
|
|
|
$mail->addCC($cc);
|
|
|
|
$mail->addBCC($bcc);
|
|
|
|
$mail->addAttachment($attachment);
|
|
|
|
|
|
|
|
// Take care of reply email addresses
|
|
|
|
if (is_array($mailreply))
|
|
|
|
{
|
|
|
|
$mail->ClearReplyTos();
|
2018-05-29 03:45:16 +00:00
|
|
|
$numReplyTo = count((array)$mailreply);
|
2017-08-20 17:52:35 +00:00
|
|
|
for ($i=0; $i < $numReplyTo; $i++)
|
|
|
|
{
|
|
|
|
$mail->addReplyTo($mailreply[$i], $replyname[$i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
elseif (!empty($mailreply))
|
|
|
|
{
|
|
|
|
$mail->ClearReplyTos();
|
|
|
|
$mail->addReplyTo($mailreply, $replyname);
|
|
|
|
}
|
2018-06-21 14:25:49 +00:00
|
|
|
|
2017-08-20 17:52:35 +00:00
|
|
|
// check if we can add the DKIM to email
|
|
|
|
if ($conf->get('enable_dkim'))
|
|
|
|
{
|
|
|
|
if (!empty($conf->get('dkim_domain')) && !empty($conf->get('dkim_selector')) && !empty($conf->get('dkim_private')) && !empty($conf->get('dkim_public')))
|
|
|
|
{
|
|
|
|
$mail->DKIM_domain = $conf->get('dkim_domain');
|
|
|
|
$mail->DKIM_selector = $conf->get('dkim_selector');
|
|
|
|
$mail->DKIM_identity = $conf->get('dkim_identity');
|
|
|
|
$mail->DKIM_passphrase = $conf->get('dkim_passphrase');
|
|
|
|
|
|
|
|
$tmp = tempnam(sys_get_temp_dir(), 'VDM');
|
|
|
|
$h = fopen($tmp, 'w');
|
|
|
|
fwrite($h, $conf->get('dkim_private'));
|
|
|
|
fclose($h);
|
|
|
|
$mail->DKIM_private = $tmp;
|
|
|
|
}
|
|
|
|
}
|
2018-06-21 14:25:49 +00:00
|
|
|
|
2017-08-20 17:52:35 +00:00
|
|
|
$sendmail = $mail->Send();
|
|
|
|
|
|
|
|
if ($conf->get('enable_dkim') && !empty($conf->get('dkim_domain')) && !empty($conf->get('dkim_selector')) && !empty($conf->get('dkim_private')) && !empty($conf->get('dkim_public')))
|
|
|
|
{
|
|
|
|
@unlink($tmp);
|
|
|
|
}
|
2018-06-21 14:25:49 +00:00
|
|
|
|
2017-08-20 17:52:35 +00:00
|
|
|
if (method_exists('ComponentbuilderHelper','storeMessage'))
|
|
|
|
{
|
2019-01-14 15:32:23 +00:00
|
|
|
// if we have active recipient details
|
|
|
|
if (isset(self::$active[$recipient]))
|
|
|
|
{
|
|
|
|
// store the massage if the method is set
|
|
|
|
ComponentbuilderHelper::storeMessage($sendmail, self::$active[$recipient], $subject, $body, $textonly, $mode, 'email');
|
|
|
|
// clear memory
|
|
|
|
unset(self::$active[$recipient]);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// store the massage if the method is set
|
|
|
|
ComponentbuilderHelper::storeMessage($sendmail, $recipient, $subject, $body, $textonly, $mode, 'email');
|
|
|
|
}
|
2017-08-20 17:52:35 +00:00
|
|
|
}
|
2018-06-21 14:25:49 +00:00
|
|
|
|
2017-08-20 17:52:35 +00:00
|
|
|
return $sendmail;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2017-08-20 20:47:14 +00:00
|
|
|
* Set html text (in a row) and subject (as title) to a email table.
|
2019-01-14 15:32:23 +00:00
|
|
|
* do not use <p> instead use <br />
|
|
|
|
* in your html that you pass to this method
|
|
|
|
* since it is a table row it does not
|
|
|
|
* work well with paragraphs
|
|
|
|
*
|
|
|
|
* @return string on success
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
public static function setBasicBody($html, $subject)
|
|
|
|
{
|
|
|
|
$body = array();
|
|
|
|
$body[] = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">";
|
|
|
|
$body[] = "<html xmlns=\"http://www.w3.org/1999/xhtml\">";
|
|
|
|
$body[] = "<head>";
|
|
|
|
$body[] = "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />";
|
|
|
|
$body[] = "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"/>";
|
|
|
|
$body[] = "<title>" . $subject . "</title>";
|
|
|
|
$body[] = "<style type=\"text/css\">";
|
|
|
|
$body[] = "#outlook a {padding:0;}";
|
|
|
|
$body[] = ".ExternalClass {width:100%;}";
|
|
|
|
$body[] = ".ExternalClass, .ExternalClass p, .ExternalClass span, .ExternalClass font, .ExternalClass td, .ExternalClass div {line-height: 100%;} ";
|
|
|
|
$body[] = "p {margin: 0; padding: 0; font-size: 0px; line-height: 0px;} ";
|
|
|
|
$body[] = "table td {border-collapse: collapse;}";
|
|
|
|
$body[] = "table {border-collapse: collapse; mso-table-lspace:0pt; mso-table-rspace:0pt; }";
|
|
|
|
$body[] = "img {display: block; outline: none; text-decoration: none; -ms-interpolation-mode: bicubic;}";
|
|
|
|
$body[] = "a img {border: none;}";
|
|
|
|
$body[] = "a {text-decoration: none; color: #000001;}";
|
|
|
|
$body[] = "a.phone {text-decoration: none; color: #000001 !important; pointer-events: auto; cursor: default;}";
|
|
|
|
$body[] = "span {font-size: 13px; line-height: 17px; font-family: monospace; color: #000001;}";
|
|
|
|
$body[] = "</style>";
|
|
|
|
$body[] = "<!--[if gte mso 9]>";
|
|
|
|
$body[] = "<style>";
|
|
|
|
$body[] = "/* Target Outlook 2007 and 2010 */";
|
|
|
|
$body[] = "</style>";
|
|
|
|
$body[] = "<![endif]-->";
|
|
|
|
$body[] = "</head>";
|
|
|
|
$body[] = "<body style=\"width:100%; margin:0; padding:0; -webkit-text-size-adjust:100%; -ms-text-size-adjust:100%;\">";
|
|
|
|
$body[] = $html;
|
|
|
|
$body[] = "</body>";
|
|
|
|
$body[] = "</html>";
|
|
|
|
|
|
|
|
return implode("\n", $body);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set html text (in a row) and subject (as title) to a email table.
|
2017-08-20 20:47:14 +00:00
|
|
|
* do not use <p> instead use <br />
|
|
|
|
* in your html that you pass to this method
|
|
|
|
* since it is a table row it does not
|
|
|
|
* work well with paragraphs
|
2017-08-20 17:52:35 +00:00
|
|
|
*
|
|
|
|
* @return string on success
|
|
|
|
*
|
|
|
|
*/
|
2017-08-20 20:47:14 +00:00
|
|
|
public static function setTableBody($html, $subject)
|
2017-08-20 17:52:35 +00:00
|
|
|
{
|
|
|
|
$body = array();
|
|
|
|
$body[] = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">";
|
|
|
|
$body[] = "<html xmlns=\"http://www.w3.org/1999/xhtml\">";
|
|
|
|
$body[] = "<head>";
|
|
|
|
$body[] = "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />";
|
|
|
|
$body[] = "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"/>";
|
2018-08-07 12:25:26 +00:00
|
|
|
$body[] = "<title>" . $subject . "</title>";
|
2017-08-20 17:52:35 +00:00
|
|
|
$body[] = "<style type=\"text/css\">";
|
|
|
|
$body[] = "#outlook a {padding:0;}";
|
|
|
|
$body[] = ".ExternalClass {width:100%;}";
|
|
|
|
$body[] = ".ExternalClass, .ExternalClass p, .ExternalClass span, .ExternalClass font, .ExternalClass td, .ExternalClass div {line-height: 100%;} ";
|
|
|
|
$body[] = "p {margin: 0; padding: 0; font-size: 0px; line-height: 0px;} ";
|
|
|
|
$body[] = "table td {border-collapse: collapse;}";
|
|
|
|
$body[] = "table {border-collapse: collapse; mso-table-lspace:0pt; mso-table-rspace:0pt; }";
|
|
|
|
$body[] = "img {display: block; outline: none; text-decoration: none; -ms-interpolation-mode: bicubic;}";
|
|
|
|
$body[] = "a img {border: none;}";
|
|
|
|
$body[] = "a {text-decoration: none; color: #000001;}";
|
|
|
|
$body[] = "a.phone {text-decoration: none; color: #000001 !important; pointer-events: auto; cursor: default;}";
|
|
|
|
$body[] = "span {font-size: 13px; line-height: 17px; font-family: monospace; color: #000001;}";
|
|
|
|
$body[] = "</style>";
|
|
|
|
$body[] = "<!--[if gte mso 9]>";
|
|
|
|
$body[] = "<style>";
|
|
|
|
$body[] = "/* Target Outlook 2007 and 2010 */";
|
|
|
|
$body[] = "</style>";
|
|
|
|
$body[] = "<![endif]-->";
|
|
|
|
$body[] = "</head>";
|
|
|
|
$body[] = "<body style=\"width:100%; margin:0; padding:0; -webkit-text-size-adjust:100%; -ms-text-size-adjust:100%;\">";
|
|
|
|
$body[] = "\n<!-- body wrapper -->";
|
|
|
|
$body[] = "<table cellpadding=\"0\" cellspacing=\"0\" border=\"0\" style=\"margin:0; padding:0; width:100%; line-height: 100% !important;\">";
|
|
|
|
$body[] = "<tr>";
|
|
|
|
$body[] = "<td valign=\"top\">";
|
|
|
|
$body[] = "<!-- edge wrapper -->";
|
|
|
|
$body[] = "<table cellpadding=\"0\" cellspacing=\"0\" border=\"0\" align=\"center\" width=\"800\" >";
|
|
|
|
$body[] = "<tr>";
|
|
|
|
$body[] = "<td valign=\"top\">";
|
|
|
|
$body[] = "<!-- content wrapper -->";
|
|
|
|
$body[] = "<table cellpadding=\"0\" cellspacing=\"0\" border=\"0\" align=\"center\" width=\"780\">";
|
|
|
|
$body[] = "<tr>";
|
|
|
|
$body[] = "<td valign=\"top\" style=\"vertical-align: top;\">";
|
|
|
|
$body[] = $html;
|
|
|
|
$body[] = "</td>";
|
|
|
|
$body[] = "</tr>";
|
|
|
|
$body[] = "</table>";
|
|
|
|
$body[] = "<!-- / content wrapper -->";
|
|
|
|
$body[] = "</td>";
|
|
|
|
$body[] = "</tr>";
|
|
|
|
$body[] = "</table>";
|
|
|
|
$body[] = "<!-- / edge wrapper -->";
|
|
|
|
$body[] = "</td>";
|
|
|
|
$body[] = "</tr>";
|
|
|
|
$body[] = "</table>";
|
|
|
|
$body[] = "<!-- / page wrapper -->";
|
|
|
|
$body[] = "</body>";
|
|
|
|
$body[] = "</html>";
|
|
|
|
|
|
|
|
return implode("\n", $body);
|
|
|
|
}
|
|
|
|
}
|