* @git 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 */ // No direct access to this JCB template file (EVER) defined('_JCB_TEMPLATE') or die; ?> ###BOM### namespace ###NAMESPACEPREFIX###\Component\###ComponentNamespace###\Administrator\Helper; use Joomla\CMS\Factory; use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Mail\Mail; use Joomla\Registry\Registry; \defined('_JEXEC') or die; /** * ###Component### component email helper * * Provides a complete and configurable mailer integration for Joomla components. * Allows for custom headers, DKIM signing, embedded images, and HTML styling. * * @since 3.0 */ abstract class ###Component###Email { /** * The active recipient. * * @var array * @since 3.0 */ public static array $active = []; /** * Mail instances container. * * @var Joomla___890fd6b1_0127_4f35_9b6e_ee6f2dc61bcc___Power[] * @since 1.7.3 */ protected static array $instances = []; /** * Global Configuration object. * * @var Registry|null * @since 5.1.1 */ protected static ?Registry $gConfig = null; /** * Component Configuration object. * * @var Registry|null * @since 3.0 */ protected static ?Registry $config = null; /** * Mailer object. * * @var Joomla___890fd6b1_0127_4f35_9b6e_ee6f2dc61bcc___Power|null * @since 3.0 */ protected static ?Joomla___890fd6b1_0127_4f35_9b6e_ee6f2dc61bcc___Power $mailer = null; /** * Custom email headers. * * @var array * @since 3.0 */ protected static array $header = []; /** * Retrieve the component configuration. * * @return Registry Component configuration object * @since 3.0 */ protected static function getConfig(): Registry { return self::$config ??= Joomla___aeb8e463_291f_4445_9ac4_34b637c12dbd___Power::getParams('com_###component###'); } /** * Retrieve the global configuration. * * @return Registry Global configuration object * @since 3.0 */ protected static function getGlobalConfig(): Registry { return self::$gConfig ??= Joomla___39403062_84fb_46e0_bac4_0023f766e827___Power::getApplication()->getConfig(); } /** * Get or create a Mailer instance. * * @return Joomla___890fd6b1_0127_4f35_9b6e_ee6f2dc61bcc___Power A cloned Mail object instance * @since 3.0 */ public static function getMailer(): Joomla___890fd6b1_0127_4f35_9b6e_ee6f2dc61bcc___Power { return self::$mailer ??= self::createMailer(); } /** * Validate an email address using a selected pattern or callable. * * @param string $address Email address to validate. * @param string|callable|null $patternselect Validation pattern or callable. * * `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 bool True if valid, false otherwise * @since 3.0 */ public static function validateAddress(string $address, $patternselect = null): bool { return self::getMailer()->validateAddress($address, $patternselect); } /** * Set a custom email header. * * @param string $key Header name. * @param string $value Header value. * * @return void * @since 3.0 */ public static function setHeader(string $key, string $value): void { self::$header[$key] = $value; } /** * Get or create a Mail instance with specific configuration. * * @param string $id Instance ID. * @param bool $exceptions Enable exceptions. * * @return Joomla___890fd6b1_0127_4f35_9b6e_ee6f2dc61bcc___Power Configured Mail instance * @since 5.1.1 */ public static function getInstance(string $id = 'Joomla', bool $exceptions = true): Joomla___890fd6b1_0127_4f35_9b6e_ee6f2dc61bcc___Power { if (!isset(self::$instances[$id])) { $config = clone self::getGlobalConfig(); $config->set('throw_exceptions', $exceptions); self::$instances[$id] = Joomla___39403062_84fb_46e0_bac4_0023f766e827___Power::getContainer()->get(Joomla___3e2779e9_b33f_42b8_a13b_53f08d99f15b___Power::class)->createMailer($config); } return self::$instances[$id]; } /** * Create a configured Mail instance. * * @return Joomla___890fd6b1_0127_4f35_9b6e_ee6f2dc61bcc___Power The created Mail object with sender, reply-to and transport settings. * @since 3.0 */ protected static function createMailer(): Joomla___890fd6b1_0127_4f35_9b6e_ee6f2dc61bcc___Power { $conf = self::getConfig(); $mailer = $conf->get('mailer', 'global'); $mail = self::getInstance(); if ($mailer === 'global') { $global = self::getGlobalConfig(); $mailer = $global->get('mailer'); $params = [ 'smtpauth' => $global->get('smtpauth') ? 1 : null, 'smtpuser' => $global->get('smtpuser'), 'smtppass' => $global->get('smtppass'), 'smtphost' => $global->get('smtphost'), 'smtpsecure' => $global->get('smtpsecure'), 'smtpport' => $global->get('smtpport'), 'sendmail' => $global->get('sendmail'), 'from' => $global->get('mailfrom'), 'name' => $global->get('fromname'), 'replyto' => $global->get('replyto'), 'replytoname' => $global->get('replytoname'), ]; } else { $params = [ 'smtpauth' => $conf->get('smtpauth') ? 1 : null, 'smtpuser' => $conf->get('smtpuser'), 'smtppass' => $conf->get('smtppass'), 'smtphost' => $conf->get('smtphost'), 'smtpsecure' => $conf->get('smtpsecure'), 'smtpport' => $conf->get('smtpport'), 'sendmail' => $conf->get('sendmail'), 'from' => $conf->get('emailfrom'), 'name' => $conf->get('fromname'), 'replyto' => $conf->get('replyto'), 'replytoname' => $conf->get('replytoname'), ]; } $mail->setSender([$params['from'], $params['name']]); if (!empty($params['replyto']) && !empty($params['replytoname'])) { $mail->ClearReplyTos(); $mail->addReplyTo($params['replyto'], $params['replytoname']); } switch ($mailer) { case 'smtp': $mail->useSMTP( $params['smtpauth'], $params['smtphost'], $params['smtpuser'], $params['smtppass'], $params['smtpsecure'], $params['smtpport'] ); break; case 'sendmail': $mail->useSendmail($params['sendmail']); $mail->IsSendmail(); break; default: $mail->IsMail(); } return $mail; } /** * Compose and send an email with full options including attachments, HTML, DKIM, and reply-to support. * * @param string|array $recipient Email or list of recipients. * @param string $subject Subject line. * @param string $body HTML body. * @param string|null $textonly Optional plain text fallback. * @param int $mode 1 = HTML, 0 = plain text. * @param string|null $bounce_email Optional bounce email address. * @param string|null $idsession Optional message tracking tag. * @param string|array|null $mailreply Optional reply-to address(es). * @param string|array|null $replyname Optional reply-to name(s). * @param string|null $mailfrom Optional sender email override. * @param string|null $fromname Optional sender name override. * @param array|null $cc CC recipients. * @param array|null $bcc BCC recipients. * @param array|string|null $attachment Attachments. * @param bool $embeded Embed image flag. * @param array|null $embeds Embedded image definitions. * * @return bool True on success, false on failure. * @since 3.0 */ public static function send( $recipient, string $subject, string $body, ?string $textonly, int $mode = 0, ?string $bounce_email = null, ?string $idsession = null, $mailreply = null, $replyname = null, ?string $mailfrom = null, ?string $fromname = null, ?array $cc = null, ?array $bcc = null, $attachment = null, bool $embeded = false, ?array $embeds = null ): bool { $mail = self::getMailer(); $conf = self::getConfig(); if ($mailfrom && $fromname) { $mail->setSender([$mailfrom, $fromname]); } if ($bounce_email) { $mail->Sender = $bounce_email; } if ($idsession) { $mail->addCustomHeader('X-VDMmethodID:' . $idsession); } foreach (self::$header as $key => $val) { $mail->addCustomHeader($key . ':' . $val); } $mail->setSubject($subject); $mail->setBody($body); if ($mode) { $mail->isHTML(true); $mail->AltBody = $textonly; } if ($embeded && !empty($embeds)) { foreach ($embeds as $embed) { $mail->addEmbeddedImage($embed->Path, $embed->FileName); } } $mail->addRecipient($recipient); if (!empty($cc)) $mail->addCC($cc); if (!empty($bcc)) $mail->addBCC($bcc); if (!empty($attachment)) $mail->addAttachment($attachment); if (!empty($mailreply)) { $mail->ClearReplyTos(); if (is_array($mailreply)) { foreach ($mailreply as $i => $reply) { $mail->addReplyTo($reply, $replyname[$i] ?? ''); } } else { $mail->addReplyTo($mailreply, (string) $replyname); } } $sent = false; $tmp = null; try { if ( $conf->get('enable_dkim') && ($domain = $conf->get('dkim_domain')) && ($selector = $conf->get('dkim_selector')) && ($privateKey = $conf->get('dkim_private')) ) { $mail->DKIM_domain = $domain; $mail->DKIM_selector = $selector; $mail->DKIM_identity = $conf->get('dkim_identity') ?: $domain; $mail->DKIM_passphrase = $conf->get('dkim_passphrase'); $tmp = tempnam(sys_get_temp_dir(), 'VDM'); if ($tmp === false || file_put_contents($tmp, $privateKey) === false) { throw new \RuntimeException('Failed to create temporary DKIM private key file.'); } $mail->DKIM_private = $tmp; } $sent = $mail->Send(); } finally { if ($tmp && file_exists($tmp)) { @unlink($tmp); } } $sent = $mail->Send(); if ($tmp) { @unlink($tmp); } if (method_exists('###Component###Helper', 'storeMessage')) { $data = self::$active[$recipient] ?? $recipient; ###Component###Helper::storeMessage($sent, $data, $subject, $body, $textonly, $mode, 'email'); unset(self::$active[$recipient]); } return $sent; } /** * Build a complete minimal HTML email body with basic headers. * Use
instead of

for layout consistency in emails. * * @param string $html Body HTML content. * @param string $subject Email subject/title used in the tag. * * @return string Full HTML email body. * @since 3.0 */ public static function setBasicBody(string $html, string $subject): string { return implode("\n", [ '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">', '<html xmlns="http://www.w3.org/1999/xhtml">', '<head>', '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />', '<meta name="viewport" content="width=device-width, initial-scale=1.0"/>', '<title>' . htmlspecialchars($subject) . '', '', '', '', '', $html, '', '' ]); } /** * Build a styled HTML email with outer table formatting for wide layout support. * Suitable for rich content emails that need outer table structure. * * @param string $html Inner body HTML content. * @param string $subject Email subject/title used in the tag. * * @return string Complete HTML email content. * @since 3.0 */ public static function setTableBody(string $html, string $subject): string { return implode("\n", [ '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">', '<html xmlns="http://www.w3.org/1999/xhtml">', '<head>', '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />', '<meta name="viewport" content="width=device-width, initial-scale=1.0"/>', '<title>' . htmlspecialchars($subject) . '', '', '', '', '', '', '
', '', '
', '', '
', $html, '
', '
', '
', '', '' ]); } }