/** * SMTP Constructor * * @param array $config Configuration for initialize the class * * @throws Exception\ServerFromAddressInvalid * @throws Exception\ServerReplyToAddressInvalid * @throws Exception\ServerReturnToAddressInvalid * @throws Exception\ServerErrorToAddressInvalid * @throws Exception\NoServerSpecified */ public function __construct(array &$config) { $typeVerified = array(); $cp = new ConfigParser($config, static::$defaultConfig); $version = Framework::getVersion(); $senderIP = IP::joinIP(Framework::core('request')->getClientInfo('ipArray'), true); $this->config['Handler'] = $version['App'] . ' ' . $version['Ver']; if ($cp->isEmpty('Servers')) { throw new Exception\NoServerSpecified(); } $this->config['Temp'] = PathParser::get($cp->getValid('TempFilesDir', function ($val) { return is_dir($val); }, sys_get_temp_dir())); $servers = $cp->get('Servers'); if ($cp->has('SelectMethod')) { switch ($cp->get('SelectMethod')) { case 'SelectMethod': shuffle($servers); break; } } foreach ($servers as $key => $val) { $serverCP = new ConfigParser($val, static::$defaultServerConfig); $mailUserName = $serverCP->get('Username'); $mailDefaultFrom = strpos($mailUserName, '@') !== false ? $mailUserName : $mailUserName . '@' . $serverCP->get('Host'); $emailFrom = $serverCP->getValid('From', function ($val) { if (empty($val)) { return false; } if (!Validator::check($val, 'email')) { throw new Exception\ServerFromAddressInvalid($val); } return true; }, $mailDefaultFrom); $this->config['Servers'][$key] = array('Host' => $serverCP->get('Host'), 'Port' => $serverCP->get('Port'), 'Type' => $serverCP->getValid('Type', function ($val) use(&$typeVerified) { if (empty($val)) { return false; } if (isset($typeVerified[$val])) { return true; } if (!isset(static::$operators[$val])) { throw new Exception\UnknownServerType($val); } $optClass = static::$operators[$val]; if (!class_exists($optClass)) { throw new Exception\OperatorClassNotFound($optClass, $val); } $parents = class_parents($optClass); if (!isset($parents)) { throw new Exception\OperatorExtendsInvalid($optClass); } $typeVerified[$val] = true; return true; }, 'General'), 'Timeout' => $serverCP->get('Timeout'), 'Retry' => $serverCP->get('Retry'), 'Username' => $mailUserName, 'Password' => $serverCP->get('Password'), 'Handler' => $this->config['Handler'], 'ScreenName' => $serverCP->get('ScreenName', $serverCP->get('Username')), 'From' => $emailFrom, 'ReplyTo' => $serverCP->getValid('ReplyTo', function ($val) { if (empty($val)) { return false; } if (!Validator::check($val, 'email')) { throw new Exception\ServerReplyToAddressInvalid($val); } return true; }, $emailFrom), 'ReturnTo' => $serverCP->getValid('ReturnTo', function ($val) { if (empty($val)) { return false; } if (!Validator::check($val, 'email')) { throw new Exception\ServerReturnToAddressInvalid($val); } return true; }, $emailFrom), 'ErrorTo' => $serverCP->getValid('ReturnTo', function ($val) { if (empty($val)) { return false; } if (!Validator::check($val, 'email')) { throw new Exception\ServerErrorToAddressInvalid($val); } return true; }, $emailFrom), 'SignCert' => PathParser::get($serverCP->getValid('SignatureCert', function ($val) { if (empty($val)) { return false; } if (!is_readable($val)) { throw new Exception\ServerSignCertNotReadable($val); } return true; }, '')), 'SignKey' => PathParser::get($serverCP->getValid('SignatureKey', function ($val) { if (empty($val)) { return false; } if (!is_readable($val)) { throw new Exception\ServerSignKeyNotReadable($val); } return true; }, '')), 'SignPass' => $serverCP->get('SignaturePass'), 'SignChain' => PathParser::get($serverCP->getValid('SignatureChain', function ($val) { if (empty($val)) { return false; } if (!is_readable($val)) { throw new Exception\ServerSignChainNotReadable($val); } return true; }, '')), 'SenderIP' => $senderIP); } }
/** * Constructor for the MIME mail builder * * @param array $mail The email in array * @param array $config Configuration */ public function __construct(array $mail, array &$config) { global $_SERVER; $senderHost = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'localhost'; $this->config = $config; $appInfo = Framework::getVersion(); $mailContent = array('Title' => isset($mail['Title']) ? $mail['Title'] : null, 'Message' => isset($mail['Message']) ? $mail['Message'] : null); $this->mail['From'] = '=?UTF-8?B?' . base64_encode($mail['ScreenName']) . '?= <' . $mail['From'] . '>'; $this->mail['Subject'] = '=?UTF-8?B?' . rtrim(base64_encode($mailContent['Title'] ? $mailContent['Title'] : '(Untitled)'), '=') . '?='; // Parse mail body $mail['Subject'] = $this->mail['Subject']; $mail['Body'] = chunk_split(base64_encode($mailContent['Message']) . '?=', 76, "\r\n"); $mail['AltBody'] = chunk_split(base64_encode(strip_tags(str_replace('</', "\r\n</", $mailContent['Message']))) . '?=', 76, "\r\n"); // Make mail header $this->addLine('MIME-Version', '1.0'); $this->addLine('User-Agent', $appInfo['App'] . ' ' . $appInfo['Ver'] . ' (' . $appInfo['Base'] . ')'); $this->addLine('X-Priority', '3'); $this->addLine('X-MSMail-Priority', 'Normal'); $this->addLine('X-Mailer', $appInfo['App'] . ' ' . $appInfo['Ver'] . ' (' . $appInfo['Base'] . ')'); $this->addLine('X-MimeOLE', $appInfo['Base'] . ' Mailer OLE'); $this->addLine('X-AntiAbuse', 'This header was added to track abuse, please include it with any abuse report'); $this->addLine('X-AntiAbuse', 'Primary Hostname - ' . $senderHost); $this->addLine('X-AntiAbuse', 'Original Domain - ' . $senderHost); $this->addLine('X-AntiAbuse', 'Originator/Caller UID/GID - [' . trim($senderHost . ' ' . $mail['SenderIP']) . '] / [' . trim($senderHost . ' ' . $mail['SenderIP']) . ']'); $this->addLine('X-AntiAbuse', 'Sender Address Domain - ' . $senderHost); // Mail title $this->addLine('Subject', $mail['Subject']); // Addresses $this->addLine('From', $this->mail['From']); $this->addLine('To', 'undisclosed-recipients:;'); $this->addLine('Return-Path', '<' . $mail['ReturnTo'] . '>'); $this->addLine('Reply-To', '<' . $mail['ReplyTo'] . '>'); $this->addLine('Errors-To', '<' . $mail['ErrorTo'] . '>'); $this->addLine('Date', date('D, d M y H:i:s O', Framework::TIME)); $this->addLine('Message-ID', md5($mail['AltBody'] . (string) $this->getFactor() . time()) . '@' . (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'localhost')); // Ready content for boundary check. Combine all content // strings to one line, then check if the boundary existed. $checkContent = $mail['Subject'] . $mail['Body'] . $mail['AltBody']; while (true) { $this->mail['Boundary'] = '#' . $this->getFactor() . '$'; $this->mail['BoundarySpliter'] = '--' . $this->mail['Boundary']; $this->mail['BoundarySpliterEnd'] = $this->mail['BoundarySpliter'] . '--'; if (strpos($checkContent, $this->mail['Boundary']) === false) { break; } } $this->addLine('Content-Type', 'multipart/alternative; boundary="' . $this->mail['Boundary'] . '"'); // Make mail body $this->addRaw(''); // Make space $this->addRaw('This MIME email produced by ' . $appInfo['Base'] . ' Mailer for ' . $senderHost . '.'); $this->addRaw('If you have any problem reading this email, please contact ' . $mail['ReturnTo'] . ' for help.'); $this->addRaw(''); // Primary content $this->addRaw($this->mail['BoundarySpliter']); $this->addLine('Content-Type', 'text/plain; charset=utf-8'); $this->addLine('Content-Transfer-Encoding', 'base64'); $this->addRaw(''); $this->addRaw($mail['AltBody']); $this->addRaw(''); $this->addRaw($this->mail['BoundarySpliter']); $this->addLine('Content-Type', 'text/html; charset=utf-8'); $this->addLine('Content-Transfer-Encoding', 'base64'); $this->addRaw(''); $this->addRaw($mail['Body']); $this->addRaw(''); $this->addRaw($this->mail['BoundarySpliterEnd']); }
/** * SMTP initializer * * @param array $cfg Configuration for initialize the class * * @return bool Return true when success, or false when fail */ public static function init(array $cfg = array()) { $version = array(); $senderIP = ''; if (empty(static::$config)) { $version = Framework::getVersion(); $senderIP = IP::joinIP(Framework::core('request')->getClientInfo('ipArray'), true); static::$config['Handler'] = $version['App'] . ' ' . $version['Ver']; if (isset($cfg['Servers']) && is_array($cfg['Servers'])) { if (isset($cfg['SelectMethod']) && $cfg['SelectMethod'] == 'Random') { shuffle($cfg['Servers']); } foreach ($cfg['Servers'] as $key => $val) { static::$config['Servers'][$key] = array('Host' => isset($val['Host']) ? $val['Host'] : 'localhost', 'Port' => isset($val['Port']) ? $val['Port'] : 25, 'Type' => isset($val['Type']) ? $val['Type'] : 'general', 'Timeout' => isset($val['Timeout']) ? $val['Timeout'] : 1, 'Username' => isset($val['Username']) ? $val['Username'] : '', 'Password' => isset($val['Password']) ? $val['Password'] : '', 'Handler' => static::$config['Handler'], 'SenderIP' => $senderIP); // Set poster screen name, this will be display on the receiver's list if (isset($val['Screenname'])) { static::$config['Servers'][$key]['Screenname'] = $val['Screenname']; } else { static::$config['Servers'][$key]['Screenname'] = static::$config['Servers'][$key]['Username']; } // Set MAIL FROM, this one must be set for future use if (isset($val['From'])) { if (Validator::check($val['From'], 'email')) { static::$config['Servers'][$key]['From'] = $val['From']; } else { throw new Exception\ServerFromAddressInvaild($val['From']); } } else { static::$config['Servers'][$key]['From'] = static::$config['Servers'][$key]['Username'] . '@' . static::$config['Servers'][$key]['Host']; } // Set REPLY TO if (isset($val['ReplyTo'])) { if (Validator::check($val['ReplyTo'], 'email')) { static::$config['Servers'][$key]['ReplyTo'] = $val['ReplyTo']; } else { throw new Exception\ServerReplyToAddressInvaild($val['ReplyTo']); } } else { static::$config['Servers'][$key]['ReplyTo'] = static::$config['Servers'][$key]['From']; } // Set RETURN TO if (isset($val['ReturnTo'])) { if (Validator::check($val['ReturnTo'], 'email')) { static::$config['Servers'][$key]['ReturnTo'] = $val['ReturnTo']; } else { throw new Exception\ServerReturnToAddressInvaild($val['ReplyTo']); } } else { static::$config['Servers'][$key]['ReturnTo'] = static::$config['Servers'][$key]['From']; } // Set ERROR TO if (isset($val['ErrorTo'])) { if (Validator::check($val['ErrorTo'], 'email')) { static::$config['Servers'][$key]['ErrorTo'] = $val['ErrorTo']; } else { throw new Exception\ServerErrorToAddressInvaild($val['ErrorTo']); } } else { static::$config['Servers'][$key]['ErrorTo'] = static::$config['Servers'][$key]['From']; } } Framework::registerHook('response_finished', 'SMTP_Sending', function () { static::sendMail(); }); Auther::init(); return true; } else { throw new Exception\NoServerSpecified(); } } return false; }