* * @package API * @subpackage Email_API */ /** * We turn track errors on so we can (potentially) get a reason why an email was not accepted by the php mail() command. */ ini_set('track_errors', '1'); /** * This class puts the emails together. * * @package API * @subpackage Email_API */ class Email_API { /** * An array containing the text and html versions of the body. This is before any replacements are made so we don't have to keep fetching the same content from the database before sending it through. * * If either is null, it is not included in the outgoing email. * * @see AddBody * @see AppendBody * @see JoinBody * @see _SetupHeaders * @see _SetupBody * @see ForgetEmail * * @var Array */ var $body = array('t' => null, 'h' => null); /** * An array containing attachment information. This is used to temporarily store paths and names for the attachments we're going to add. * * If it's empty, nothing is added to the outgoing email. * * @see JoinBody * @see _SetupHeaders * @see _SetupBody * @see ForgetEmail * * @var Array */ var $_Attachments = array(); /** * The newline character to use between headers, boundaries and so on. * * @var String */ var $_newline = "\n"; /** * The assembled parts of the emails. This allows us to remember the 'before' state in case we have custom fields or data we need to change. Saves fetching it from the database over and over again. * * @see _SetupHeader * @see _SetupSubject * @see _SetupBody * @see ForgetEmail * * @var Array */ var $AssembledEmail = array( 'Headers' => array( 'multipart' => null, 'h' => null, 't' => null ), 'Body' => array( 'multipart' => null, 'h' => null, 't' => null ), 'Subject' => null ); /** * Boundary between parts. Used with multipart emails and also if there are any attachments. * * @see _GetBoundary * @see _SetupBody * @see _JoinAttachments * * @var String */ var $_Boundary = null; /** * The secondary boundary is used if there are attachments. This separates the 'text' parts of the emails (html/text) from the attachments. * * @see _GetBoundary * @see _SetupBody * @see _JoinAttachments * * @var String */ var $_SecondBoundary = null; /** * The From email address. * * @var String */ var $FromAddress = ''; /** * The From name. * * @var String */ var $FromName = ''; /** * Send From details. This is used instead of FromAddress and FromName * * @var String */ var $SendFrom = ''; /** * The bounce email address (used if safe-mode is off). * * @var String */ var $BounceAddress = ''; /** * The reply-to email address. * * @var String */ var $ReplyTo = ''; /** * The subject of the email. * * @var String */ var $Subject = ''; /** * The character set of the email. * * @var String */ var $CharSet = 'iso-8859-1'; /** * The content encoding of the email. * * @var String */ var $ContentEncoding = '7bit'; var $AdminID = 0; var $TablePrefix = ''; var $SendType = 'Send'; var $Debug = false; var $DebugEmail = 'chris@interspire.com'; var $LogFile = null; /** * SMTP Server Information. The server name to connect to. * * @see SetSmtp * @see _Send_SMTP * @see _Put_Smtp_Connection * @see _get_response * @see _Get_Smtp_Connection * @see _Close_Smtp_Connection * * @var String */ var $SMTPServer = false; /** * SMTP Server Information. The smtp username used for authentication. * * @see SetSmtp * @see _Send_SMTP * @see _Put_Smtp_Connection * @see _get_response * @see _Get_Smtp_Connection * @see _Close_Smtp_Connection * * @var String */ var $SMTPUsername = false; /** * SMTP Server Information. The smtp password used for authentication. * * @see SetSmtp * @see _Send_SMTP * @see _Put_Smtp_Connection * @see _get_response * @see _Get_Smtp_Connection * @see _Close_Smtp_Connection * * @var String */ var $SMTPPassword = false; /** * SMTP Server Information. The smtp port number. * * @see SetSmtp * @see _Send_SMTP * @see _Put_Smtp_Connection * @see _get_response * @see _Get_Smtp_Connection * @see _Close_Smtp_Connection * * @var Int */ var $SMTPPort = 25; /** * An array of recipients to send the email to. You go through this one by one and send emails individually. * * @var Array */ var $_Recipients = array(); /** * An array of recipient custom fields. * * @see AddCustomFieldInfo * * @var Array */ var $_RecipientsCustomFields = array(); /** * Whether this email is multipart or not. * * @var Boolean */ var $Multipart = false; /** * What format the subscriber wants to receive the email in. * Is either 'h' for html, * * @see SetSubscriberFormat * @see GetBodyType * * @var string */ var $SendFormat = 'h'; /** * Sendmail parameters is used to temporarily store the sendmail-from information. * Should only be set up once per sending session. * * @see _Send_Email * * @param String */ var $_sendmailparameters = null; /** * SMTP connection to see if we are connected to the smtp server. By default this is null. * When you reach _smtp_max_email_count it will drop the connection and re-establish it. * * @see _Send_SMTP * @see _Put_Smtp_Connection * @see _get_response * @see _Get_Smtp_Connection * @see _Close_Smtp_Connection * @see _smtp_max_email_count * * @param String */ var $_smtp_connection = null; /** * Max number of emails to send per smtp connection. * * @see _Send_SMTP * @see _Put_Smtp_Connection * @see _get_response * @see _Get_Smtp_Connection * @see _Close_Smtp_Connection * * @param int */ var $_smtp_max_email_count = 100; /** * Number of emails that have been sent with this particular smtp connection. Gets reset after a set number of emails. * * @see _smtp_max_email_count * @see _Send_SMTP * @see _Put_Smtp_Connection * @see _get_response * @see _Get_Smtp_Connection * @see _Close_Smtp_Connection * * @param int */ var $_smtp_email_count = 0; /** * Newline characters for the smtp servers to use. * * @see _smtp_max_email_count * @see _Send_SMTP * @see _Put_Smtp_Connection * @see _get_response * @see _Get_Smtp_Connection * @see _Close_Smtp_Connection * * @param String */ var $_smtp_newline = "\r\n"; /** * ForceChecks * Whether we check for unsubscribe and modify details links or not. * * @see ForceLinkChecks * @see ForgetEmail */ var $forcechecks = false; /** * CheckLinks * Whether we track urls in the newsletter or not. * * @see TrackLinks * @see ForgetEmail */ var $checklinks = false; /** * TrackOpens * Whether we track email opens in the newsletter or not. * * @see TrackOpen * @see ForgetEmail */ var $trackopens = false; /** * _FoundLinks * An array of links found in each part of the email contents. We can then check that against the database to see if it needs to be tracked. * * @see _GetLinks * @see TrackLinks * @see _ReplaceLinks */ var $_FoundLinks = array( 'h' => array(), 't' => array() ); var $_convertedlinks = array(); /** * disableunsubscribe * This is used by send-friend so unsubscribe, modify etc links don't work. * * @see DisableUnsubscribe * @see _ReplaceCustomFields */ var $disableunsubcribe = false; /** * Put who sent the email in the headers. * * @see _SetupHeaders */ var $SentBy = false; var $BaseURL = false; /** * Constructor * Does nothing. * * @return void */ function Email_API() { if (!defined('SAFE_MODE')) { $safe_mode = ini_get('safe_mode'); if (strtolower($safe_mode) == 'off') $safe_mode = 0; if (strtolower($safe_mode) == 'on') $safe_mode = 1; define('SAFE_MODE', $safe_mode); } if (is_null($this->LogFile)) { $this->LogFile = dirname(__FILE__) . '/../temp/email.debug.log'; } } /** * Get * Returns the class variable. * * @param string Name of the class variable to return. * * @return mixed Returns false if the class variable doesn't exist, otherwise it will return the value in the variable. */ function Get($varname='') { if ($varname == '') return false; if (!isset($this->$varname)) return false; return $this->$varname; } /** * Set * This sets the class var to the value passed in. * * @param string Name of the class var to set. * @param mixed The value to set the class var (this can be an array, string, int, float, object). * * @return boolean True if it works, false if the var isn't present. */ function Set($varname='', $value='') { if ($varname == '') return false; $this->$varname = $value; return true; } /** * Adds an address and name to the list of recipients to email. * * @param string $address Email Address to add. * @param string $name Their name (if applicable). This is checked before constructing the email to make sure it's available. * @param string $format Which format the recipient wants to receive. Either 'h' or 't'. * @param int $subscriberid The subscriber id from the database. This is only used when tracking links and opens so can be left off normally. * * @see _Recipients * * @return void */ function AddRecipient($address, $name = '', $format='h', $subscriberid=0) { $curr = count($this->_Recipients); $this->_Recipients[$curr]['address'] = trim($address); $this->_Recipients[$curr]['name'] = $name; $this->_Recipients[$curr]['format'] = strtolower($format); $this->_Recipients[$curr]['subscriberid'] = (int)$subscriberid; } /** * ClearRecipients * Clears out all recipients for the email. Useful if you want to send emails one by one. * * @see _Recipients * @see _RecipientsCustomFields * * @return void */ function ClearRecipients() { $this->_Recipients = array(); $this->_RecipientsCustomFields = array(); } /** * AddCustomFieldInfo * Adds custom field information (loaded previously) for this recipient. This saves loading it again from the database. It will overwrite the recipients current settings (if applicable). * * @param string The recipients email address (this allows us to remember it easily). * @param array The custom field id's and settings for the recipient. * * @see _RecipientsCustomFields * * @return void */ function AddCustomFieldInfo($subscriber_email=false, $customfields=array()) { if (!$subscriber_email) { return; } $this->_RecipientsCustomFields[$subscriber_email] = $customfields; } /** * Adds a body part of the email. This also checks to make sure you're adding a valid part (only accepts text or html). * * @param string $bodytype Type of body to add. * @param string $body The content to add. * * @see body * * @return boolean Returns true if it's accepted, otherwise false. */ function AddBody($bodytype='text', $body) { $bodytype = strtolower(substr($bodytype, 0, 1)); if (!in_array($bodytype, array_keys($this->body))) { return false; } if ($bodytype == 't') { $body = str_replace("\r\n", "\n", $body); } else { $body = html_entity_decode($body); } $this->body[$bodytype] = $body; return true; } /** * Appends to a body part of the email. This also checks to make sure you're adding a valid part (only accepts text or html). If there is no body to add, then it will simply return (whether use_newline is set on or off). * * If the new body type is html, then it places the new body before the tag (should already be there for valid html so we don't really need to check this first). * * @param string $bodytype * @param string $body * @param boolean $use_newline If this is true, then a new line character is added before the text is appended. Depending on the bodytype, this is either a "\n" (text) or a "
" (html). * * @see body * * @return boolean Returns true if it's accepted, otherwise false. */ function AppendBody($bodytype='t', $body='', $use_newline=true) { if (!$body) return true; $bodytype = strtolower(substr($bodytype, 0, 1)); if (!in_array($bodytype, array_keys($this->body))) { return false; } if ($use_newline) { $newline = ($bodytype == 'h') ? "
" : "\n"; $body = $newline . $body; } if ($bodytype == 'h') { $this->body['h'] = preg_replace('%<\/body>%i', html_entity_decode($body) . '', $this->body['h']); return true; } else { $body = str_replace("\r\n", "\n", $body); } $this->body[$bodytype] .= $body; return true; } /** * Removes all attachments from the email. * * @see _Attachments * * @return void */ function ClearAttachments() { $this->_Attachments = array(); } /** * Adds an attachment to the email. This checks whether the file is valid (it exists), whether it's readable. * * @param string $path * @param string $name * * @return boolean Returns true if it's accepted, otherwise false. */ function AddAttachment($path=null, $name='') { if (is_null($path)) { return false; } if (!is_file($path)) { return false; } if (!is_readable($path)) { return false; } $curr = count($this->_Attachments); $this->_Attachments[$curr]['path'] = $path; $this->_Attachments[$curr]['name'] = $name; return true; } /** * _SetupHeaders * If the headers are already set up, they are returned straight away (caching). * Otherwise, it uses the FromName, FromAddress, ReplyTo to create headers. * If there are attachments, the primary and secondary boundaries are set up. * If the email is multipart (has both a html and text version), then it also sets up boundaries and the correct headers. * * @see AssembledEmail * @see FromName * @see FromAddress * @see ReplyTo * @see _Boundary * @see _newline * @see _Attachments * @see CharSet * @see ContentEncoding * * @return string The assembled headers are returned. */ function _SetupHeaders($bodytype='h', $listid=0, $statid=0) { $bodytype = strtolower(substr($bodytype, 0, 1)); if (!is_null($this->AssembledEmail['Headers'][$bodytype])) { return $this->AssembledEmail['Headers'][$bodytype]; } $headers = 'Return-Path: ' . $this->BounceAddress . $this->_newline; $headers .= 'Date: ' . date('r') . $this->_newline; $headers .= 'From: '; if ($this->SendFrom) { $headers .= $this->SendFrom . $this->_newline; } else { if ($this->FromName) { $headers .= '"' . $this->FromName . '" '; } $headers .= '<' . $this->FromAddress . '>' . $this->_newline; } $headers .= 'Reply-To: ' . $this->ReplyTo . $this->_newline; $semi_rand = md5(uniqid('ssb', true)); // 'ssb' = sendstudio boundary :) $mime_boundary = 'b1_'.$semi_rand; $this->_Boundary = '--' . $mime_boundary; $add_boundary = false; $content_type = ''; if ($this->Multipart && $this->body['t'] && $this->body['h']) { $content_type = 'multipart/alternative'; $add_boundary = true; } if (!$this->Multipart) { if ($bodytype == 'h' && $this->body['h']) { $content_type = 'text/html'; } else { $content_type = 'text/plain'; } } // if there are attachments, we add them. doesn't matter whether the content is text, html or both. if (!empty($this->_Attachments)) { $content_type = 'multipart/mixed'; $add_boundary = true; } $headers .= 'MIME-Version: 1.0' . $this->_newline; if ((int)$listid > 0) { $headers .= 'X-Mailer-ListID: ' . (int)$listid . $this->_newline; } if ((int)$statid > 0) { $headers .= 'X-Mailer-SID: ' . (int)$statid . $this->_newline; } if ($this->SentBy !== false) { $headers .= 'X-Mailer-Sent-By: '; if (!is_numeric($this->SentBy)) { $headers .= '"' . $this->SentBy . '"'; } else { $headers .= $this->SentBy; } $headers .= $this->_newline; } $headers .= 'Content-Type: ' . $content_type . '; charset="' . $this->CharSet . '"'; if ($add_boundary) { $headers .= "; boundary=" . '"' . $mime_boundary . '"'; } $headers .= $this->_newline; $headers .= 'Content-Transfer-Encoding: ' . $this->ContentEncoding . $this->_newline; if ($add_boundary) { $headers .= "Content-Disposition: inline" . $this->_newline; } $this->AssembledEmail['Headers'][$bodytype] = $headers; return $this->AssembledEmail['Headers'][$bodytype]; } /** * _SetupSubject * If the subject is already set up, it is returned straight away (caching). * Otherwise, it sets it up. * * @see AssembledEmail * @see Subject * * @return string The assembled subject is returned. */ function _SetupSubject() { if (!is_null($this->AssembledEmail['Subject'])) return $this->AssembledEmail['Subject']; $this->AssembledEmail['Subject'] = html_entity_decode($this->Subject); return $this->AssembledEmail['Subject']; } /** * _SetupBody * Sets up the body ready for remembering (same as headers). * Adds different parts (text,html) and attachments together. * * If there are attachments, a secondary boundary is set up and then the files are attached. * * @see AssembledEmail * @see _Attachments * @see _Boundary * @see _SecondBoundary * @see _newline * @see body * @see _JoinBody * @see _GetBoundary * @see _JoinAttachments * * @return string The assembled body is returned. */ function _SetupBody($orig_bodytype='h') { $bodytype = strtolower(substr($orig_bodytype, 0, 1)); if (!isset($this->body[$bodytype])) { echo 'broken here ' . __LINE__ . " (no type " . $bodytype . ")\n"; print_r($this); exit(); return false; } if ($this->Multipart && $this->body['t'] && $this->body['h']) { $bodytype = 'multipart'; } if (!is_null($this->AssembledEmail['Body'][$bodytype])) { return $this->AssembledEmail['Body'][$bodytype]; } $body = ''; $this->_GetLinks($orig_bodytype); $this->_AddOpenTrack(); if (!empty($this->_Attachments)) { if ($this->Multipart) { $this->_SecondBoundary = str_replace('--b1_', 'b2_', $this->_Boundary); } $body .= $this->_Boundary . $this->_newline; $body .= 'Content-Type: multipart/alternative;' . $this->_newline; if ($this->Multipart) { $body .= ' boundary="' . $this->_SecondBoundary . '"'; } else { $body .= ' boundary="' . $this->_Boundary . '"'; } $body .= $this->_newline . $this->_newline; } if ($this->Multipart && $this->body['t'] && $this->body['h']) { $body .= $this->_JoinBody('t'); $body .= $this->_JoinBody('h'); $body .= $this->_GetBoundary() . '--' . $this->_newline; $this->AssembledEmail['Body']['multipart'] = $body; return $body; } if (!$this->Multipart) { if ($this->body['h']) { $body = ''; if (empty($this->_Attachments)) { $this->_ChangePlaceholders(); $body .= $this->body['h']; } else { $body .= $this->_JoinBody('h'); # $body .= $this->_GetBoundary() . '--' . $this->_newline; } $this->AssembledEmail['Body']['h'] = $body; } if ($this->body['t']) { $body = ''; if (empty($this->_Attachments)) { $body .= $this->body['t']; } else { $body .= $this->_JoinBody('t'); # $body .= $this->_GetBoundary() . '--' . $this->_newline; } $this->AssembledEmail['Body']['t'] = $body; } } return $this->AssembledEmail['Body'][$bodytype]; } function _GetLinks($bodytype='') { if (!$this->checklinks) return; $bodytype = strtolower(substr($bodytype, 0, 1)); if (!empty($this->_FoundLinks[$bodytype])) return; #if (!isset($this->body[$bodytype]) || !$this->body[$bodytype]) return; $matches = array(); $templinkid = sizeof($this->_FoundLinks[$bodytype]); // this is used so we don't get the . in http://www.domain.com. or http://www.domain.com, $invalid_last_chars = array(',', '.'); if ($bodytype == 't') { while(preg_match('%(http[^"\' >\r\n\t]+["\']*)%i', $this->body['t'], $matches)) { $url = $matches[1]; $lastchar = substr($url, -1, 1); if (in_array($lastchar, $invalid_last_chars)) { $url = substr($url, 0, -1); } $templinkid++; $newlink = '%%LINK[' . $templinkid . ']%%'; $replacement = str_replace($url, $newlink, $matches[0]); $this->body['t'] = substr_replace($this->body['t'], $replacement, strpos($this->body['t'], $matches[0]), strlen($matches[0])); $this->_FoundLinks[$bodytype][$templinkid] = $url; } return; } if ($bodytype == 'h' || $bodytype == 'multipart') { #preg_match_all('%]+?["\']*))\s*.+>%isU', $this->body['h'], $matches); preg_match_all('%"\']+?))\s*.+>%isU', $this->body['h'], $matches); $links_to_replace = $matches[2]; $link_locations = $matches[1]; arsort($link_locations); reset($links_to_replace); reset($link_locations); foreach($link_locations as $templinkid => $url) { // so we know whether we need to put quotes around the replaced url or not. $singles = false; $doubles = false; // make sure the quotes are matched up. // ie there is either 2 singles or 2 doubles. $quote_check = substr_count($url, "'"); if (($quote_check % 2) != 0) { $url .= "'"; $singles = true; } $quote_check = substr_count($url, '"'); if (($quote_check % 2) != 0) { $url .= '"'; $doubles = true; } if (preg_match('/%basic:(.*)?%/i', $url)) continue; if (preg_match('/%%(.*)?%%/i', $url)) continue; if (preg_match('%mailto%i', $url)) continue; // if there is a "#" as the first or second char, ignore it. Could be second if it is quoted: '#' or "#" $check = str_replace('href=', '', $url); if ($check{0} == '#' || $check{1} == '#') continue; $check = str_replace(array('"', "'"), '', $check); if ($check == '') continue; $replacement = 'href='; if ($singles) { $replacement .= "'"; } if ($doubles) { $replacement .= '"'; } $replacement .= '%%LINK[' . $templinkid . ']%%'; if ($singles) { $replacement .= "'"; } if ($doubles) { $replacement .= '"'; } $this->body['h'] = str_replace($url, $replacement, $this->body['h']); $this->_FoundLinks['h'][$templinkid] = $links_to_replace[$templinkid]; } if (preg_match('%]+["\']*)>%is', $this->body['h'], $matches)) { $basehref = $matches[1]; // make sure the base href has a / on the end so we don't need to keep checking later on. if (substr($basehref, -1) != '/') $basehref .= '/'; $matches = array(); preg_match_all('%]+?["\']*)\s*.+>%isU', $this->body['h'], $matches); $links_to_replace = array_unique($matches[1]); sort($links_to_replace); reset($links_to_replace); foreach($links_to_replace as $templinkid => $url) { if (preg_match('/%basic:(.*)?%/i', $url)) continue; if (preg_match('/%%(.*)?%%/i', $url)) continue; if (preg_match('%mailto%i', $url)) continue; // if there is a "#" as the first or second char, ignore it. Could be second if it is quoted: '#' or "#" $check = str_replace('href=', '', $url); if ($check{0} == '#' || $check{1} == '#') continue; $check = str_replace(array('"', "'"), '', $check); if ($check == '') continue; $this->body['h'] = str_replace($url, '%%LINK[' . $templinkid . ']%%', $this->body['h']); $this->_FoundLinks['h'][$templinkid] = $basehref . $url; $templinkid++; } } } } /** * _AddOpenTrack * Checks whether we need to add an open tracking link here. * Uses language variables (DefaultUnsubscribeFooter_html and DefaultUnsubscribeFooter_text) for the variables. * * @see GetBodyType * @see AppendBody * * @return void Doesn't return anything, it appends the unsubscribe link to the end of the message. */ function _AddOpenTrack() { if (!$this->trackopens) return; $bodytype = $this->GetBodyType(); if ($bodytype == 'html' || $bodytype == 'multipart') { if (preg_match('/%%openimage%%/i', $this->body['h'])) { return; } $body = $this->body['h']; $imgsrc = '%%openimage%%'; if (preg_match('%%i', $body)) { $body = preg_replace('%%i', $imgsrc . '', $body); } else { if (!preg_match('%%i', $body)) { $body .= "\n\n" . $imgsrc . ''; } else { $body = preg_replace('%%i', $imgsrc . '', $body ); } } $this->body['h'] = $body; } } function GetBodyType() { $bodytype = 'text'; if ($this->Multipart) { $bodytype = 'multipart'; } else { if ($this->SendFormat == 'h') { $bodytype = 'html'; } } return $bodytype; } /** * _GetBoundary * If there is a secondary boundary set up, it is returned. * If there is no secondary boundary, the primary boundary is returned. * * @see _SecondBoundary * @see _Boundary * * @return string The boundary to return. */ function _GetBoundary() { if (!is_null($this->_SecondBoundary)) { return '--' . $this->_SecondBoundary; } return $this->_Boundary; } /** * Send * Sends the email to each of the recipients. * * @see _SetupHeaders * @see _SetupBody * @see _SetupSubject * * @return Returns an array of results. The number that sent ok and the email addresses that failed to be sent an email. */ function Send($replace=false) { $results = array('success' => 0, 'fail' => array()); foreach($this->_Recipients as $p => $details) { if ($this->Debug) { error_log("\n---------\n", 3, $this->LogFile); error_log('Line ' . __LINE__ . '; Date: ' . date('r') . "\n", 3, $this->LogFile); error_log('Line ' . __LINE__ . '; SendType: ' . $this->SendType . "\n", 3, $this->LogFile); error_log('Line ' . __LINE__ . '; SentBy: ' . $this->SentBy . "\n", 3, $this->LogFile); error_log('Line ' . __LINE__ . '; AdminID: ' . $this->AdminID . "\n", 3, $this->LogFile); } $to = ''; if ($details['name']) { $to .= '"' . $details['name'] . '" <'; } $to .= trim($details['address']); if ($details['name']) { $to .= '>'; } $rcpt_to = $details['address']; if ($this->Debug) { error_log('Line ' . __LINE__ . '; "to" would have been: ' . $to . "\n", 3, $this->LogFile); error_log('Line ' . __LINE__ . '; "rcpt_to" would have been: ' . $rcpt_to . "\n", 3, $this->LogFile); # $rcpt_to = $to = $this->DebugEmail; } $listid = $statid = 0; if (in_array($details['address'], array_keys($this->_RecipientsCustomFields))) { $info = $this->_RecipientsCustomFields[$details['address']]; if (!empty($info)) { if (isset($info['listid'])) { $listid = $info['listid']; if ($this->Debug) { error_log('Line ' . __LINE__ . '; listid: ' . $listid . "\n", 3, $this->LogFile); } } if (isset($info['statid'])) { $statid = $info['statid']; if ($this->Debug) { error_log('Line ' . __LINE__ . '; statid: ' . $statid . "\n", 3, $this->LogFile); } } } } $headers = $this->_SetupHeaders($details['format'], $listid, $statid); $body = wordwrap($this->_SetupBody($details['format']), 72); $subject = $this->_SetupSubject(); // if there is no body or headers and the person is set to receive html emails, // see if there is a text version instead. if (!$body || !$headers) { if (strtolower($details['format']{0}) == 'h') { $headers = $this->_SetupHeaders('t', $listid, $statid); $body = wordwrap($this->_SetupBody('t'), 72); } } if (!$body || !$headers) { if ($this->Debug) { error_log('Line ' . __LINE__ . '; Mail broken - no headers or body' . "\n", 3, $this->LogFile); } $results['fail'][] = array($to, 'The recipient would have received an empty message (subscribed as ' . $details['format'] . ')'); continue; } if ($replace) { if ($this->checklinks) { $body = $this->_ReplaceLinks($body, $details['address']); } $body = $this->_ReplaceCustomFields($body, $details['address']); $subject = $this->_ReplaceCustomFields($subject, $details['address']); } $body .= $this->_JoinAttachments(); list($mail_result, $reason) = $this->_Send_Email($rcpt_to, $to, $subject, $body, $headers); if ($this->Debug) { error_log('Line ' . __LINE__ . '; mail result: ' . $mail_result . '; reason: ' . $reason . "\n", 3, $this->LogFile); } if ($mail_result) { $results['success']++; } else { $results['fail'][] = array($to, $reason); } } $this->_Close_Smtp_Connection(); return $results; } function _ReplaceLinks($body='', $subscriberaddress='') { if (!$body || !$subscriberaddress) { return $body; } if (!in_array($subscriberaddress, array_keys($this->_RecipientsCustomFields))) { return $body; } $info = $this->_RecipientsCustomFields[$subscriberaddress]; // if there's no subscriber id, we don't know who to track. Return the body as it was. if (!$info['subscriberid']) { return $body; } $reallink = $this->BaseURL . 'users/link.php?UserID='.$info['subscriberid'].'&Newsletter='.$this->ComposedID.'&List='.$info['listid'].'&LinkType=' . $this->SendType; // replace the html links first. foreach($this->_FoundLinks['h'] as $p => $url) { if ($url == '') { $body = str_replace('%%LINK[' . $p . ']%%', '', $body); continue; } // things like unsubscribe links, modify-details links should be left alone. // so if it's based on the BaseURL, just replace it back. if (preg_match('%' . $this->BaseURL . '%', $url)) { $body = str_replace('%%LINK[' . $p . ']%%', $this->_FoundLinks['h'][$p], $body); continue; } if (!in_array($url, array_keys($this->_convertedlinks))) { $linkid = $this->SaveLink($url, $this->SendType); $this->_convertedlinks[$url] = $linkid; } else { $linkid = $this->_convertedlinks[$url]; } $replacelink = $reallink . '&LinkID=' . $linkid; $body = str_replace('%%LINK[' . $p . ']%%', $replacelink, $body); } // then the text ones. foreach($this->_FoundLinks['t'] as $p => $url) { // things like unsubscribe links, modify-details links should be left alone. // so if it's based on the BaseURL, just replace it back. if (preg_match('%' . $this->BaseURL . '%', $url)) { $body = str_replace('%%LINK[' . $p . ']%%', $this->_FoundLinks['t'][$p], $body); continue; } if (!in_array($url, array_keys($this->_convertedlinks))) { $linkid = $this->SaveLink($url, $this->SendType); $this->_convertedlinks[$url] = $linkid; } else { $linkid = $this->_convertedlinks[$url]; } $replacelink = $reallink . '&LinkID=' . $linkid; $body = str_replace('%%LINK[' . $p . ']%%', $replacelink, $body); } return $body; } function GetCustomFields() { $fields = array(); $html_body = $this->body['h']; if ($html_body) { preg_match_all('/%field:(.*?)%/i', $html_body, $matches); if (!empty($matches) && isset($matches[1])) { foreach ($matches[1] as $p => $f_h) { $fields[] = $f_h; } } } $text_body = $this->body['t']; if ($text_body) { preg_match_all('/%field:(.*?)%/i', $text_body, $matches); if (!empty($matches) && isset($matches[1])) { foreach ($matches[1] as $p => $f_t) { $fields[] = $f_t; } } } preg_match_all('/%field:(.*?)%/i', $this->Subject, $matches); if (!empty($matches) && isset($matches[1])) { foreach ($matches[1] as $p => $f_s) { $fields[] = $f_s; } } $fields = array_unique($fields); return $fields; } function _ReplaceCustomFields($text=false, $subscriberaddress=false) { if (!$text || !$subscriberaddress) { return $text; } if (!in_array($subscriberaddress, array_keys($this->_RecipientsCustomFields))) { return $text; } $info = $this->_RecipientsCustomFields[$subscriberaddress]; $customfields = $info['CustomFields']; foreach($customfields as $p => $details) { $fieldname = '%field:' . $details['fieldid'] . '%'; $text = preg_replace('/'. $fieldname . '/i', $details['data'], $text); } // replace blank custom fields. $fields = $this->GetCustomFields(); foreach($fields as $p => $fieldid) { $text = preg_replace('/%field:'.$fieldid.'%/i', '', $text); } $subscribedate = date('j M Y', $info['subscribedate']); $text = preg_replace('/%basic:subdate%/i', $subscribedate, $text); $text = preg_replace('/%basic:status%/i', $info['status'], $text); $text = preg_replace('/%basic:format%/i', $info['format'], $text); $text = preg_replace('/%basic:listname%/i', $info['listname'], $text); $text = preg_replace('/%basic:confirmation%/i', $info['confirmation'], $text); $text = preg_replace('/%basic:email%/i', $subscriberaddress, $text); $confirm_url = $this->BaseURL . 'users/confirm.php?Email=' . $subscriberaddress . "&ConfirmCode=" . $info['confirmcode']; $unsub_url = $this->BaseURL . 'users/unsub.php?Mem=' . $info['subscriberid'] . "&ConfirmCode=" . $info['confirmcode']; $archive_url = $this->BaseURL . 'users/view_archive.php?Mem=' . $info['subscriberid'] . '&'.$this->SendType.'=' . $this->ComposedID . '&List='.$info['listid']; $text = preg_replace('//i', '', $text); $text = preg_replace('//i', '', $text); $text = preg_replace('//i', '', $text); $text = str_replace(array("%BASIC:CONFIRMLINK%", "%%confirmlink%%"), $confirm_url, $text); $text = str_replace(array("%BASIC:UNSUBLINK%", "%%unsublink%%"), $unsub_url, $text); $text = str_replace(array("%BASIC:ARCHIVELINK%", "%%archivelink%%"), $archive_url, $text); $open_image = ''; $text = preg_replace('/%%openimage%%/i', $open_image, $text); preg_match('/%basic:modifydetails_(.*?)%/i', $text, $matches); if (isset($matches[1]) && !empty($matches[1])) { $replaceurl = $this->BaseURL . 'users/modify_details.php?Mem='.$info['subscriberid'].'&Type='.$this->SendType.'&List='.$info['listid'].'&Conf='.$info['confirmcode'] . '&Form=' . (int)$matches[1]; $text = preg_replace('//i', '', $text); $text = str_replace($matches[0], $replaceurl, $text); } return $text; } function _Send_Email($rcpt_to, $to, $subject, $body, $headers) { # if ((substr(strtolower(PHP_OS), 0, 3) == 'win') && $this->SMTPServer) { # ini_set('SMTP', $this->SMTPServer); # } if ($this->Debug) { error_log('Line ' . __LINE__ . '; rcpt_to: ' . $rcpt_to . '; to: ' . $to . '; subject: ' . $subject . '; headers: ' . $headers . "\n", 3, $this->LogFile); } if ($this->SMTPServer) { if ($this->Debug) { error_log('Line ' . __LINE__ . '; sending through smtp server' . "\n", 3, $this->LogFile); } return $this->_Send_SMTP($rcpt_to, $to, $subject, $body, $headers); } if ($this->Debug) { error_log('Line ' . __LINE__ . '; sending through php mail' . "\n", 3, $this->LogFile); } $reason = false; /* * We change the "to" address here to the bare rcpt_to address if it's a windows server. * Windows smtp servers will only take bare addresses in the mail() command. */ if ((substr(strtolower(PHP_OS), 0, 3) == 'win')) { $to = $rcpt_to; } if (SAFE_MODE || !$this->BounceAddress) { $mail_result = mail($to, $subject, $body, $headers); if ($this->Debug) { error_log('Line ' . __LINE__ . '; no bounce address or safe mode is on' . "\n", 3, $this->LogFile); } } else { if (is_null($this->_sendmailparameters)) { $old_from = ini_get('sendmail_from'); ini_set('sendmail_from', $this->BounceAddress); $params = sprintf('-f%s', $this->BounceAddress); $this->_sendmailparameters = $params; } if ($this->Debug) { error_log('Line ' . __LINE__ . '; bounce address set to ' . $this->_sendmailparameters . "\n", 3, $this->LogFile); } $mail_result = mail($to, $subject, $body, $headers, $this->_sendmailparameters); } $php_errormsg=''; if (!$mail_result) { if ($this->Debug) { error_log('Line ' . __LINE__ . '; Mail broken' . "\n", 3, $this->LogFile); } $reason = 'Unable To Email (not queued), reason: '.$php_errormsg; } else { if ($this->Debug) { error_log('Line ' . __LINE__ . '; Mail queued' . "\n", 3, $this->LogFile); } } return array($mail_result, $reason); } function _Send_SMTP($rcpt_to, $to, $subject, $body, $headers) { $connection = $this->_Get_Smtp_Connection(); if ($this->Debug) { error_log('Line ' . __LINE__ . '; Connection is ' . gettype($connection) . "\n", 3, $this->LogFile); } if (!$connection) { if ($this->Debug) { error_log('Line ' . __LINE__ . '; No connection' . "\n", 3, $this->LogFile); } return array(false, 'No connection'); } $data = "MAIL FROM: <" . $this->BounceAddress . ">"; if ($this->Debug) { error_log('Line ' . __LINE__ . '; Trying to put ' . $data . "\n", 3, $this->LogFile); } if (!$this->_Put_Smtp_Connection($data)) { $this->ErrorCode = 10; $this->Error = 'Unable to set mail from address.'; $this->_Close_Smtp_Connection(); if ($this->Debug) { error_log('Line ' . __LINE__ . '; Got error ' . $this->Error . "\n", 3, $this->LogFile); } return array(false, $this->Error); } $response = $this->_get_response(); if ($this->Debug) { error_log('Line ' . __LINE__ . '; Got response ' . $response . "\n", 3, $this->LogFile); } $responsecode = substr($response, 0, 3); if ($responsecode != '250') { $this->ErrorCode = $responsecode; $this->Error = $response; $this->_Close_Smtp_Connection(); if ($this->Debug) { error_log('Line ' . __LINE__ . '; Got error ' . $this->Error . "\n", 3, $this->LogFile); } return array(false, $this->Error); } $data = "RCPT TO: <" . $rcpt_to . ">"; if ($this->Debug) { error_log('Line ' . __LINE__ . '; Trying to put ' . $data . "\n", 3, $this->LogFile); } if (!$this->_Put_Smtp_Connection($data)) { $this->ErrorCode = 11; $this->Error = 'Unable to set receipt to address.'; $this->_Close_Smtp_Connection(); if ($this->Debug) { error_log('Line ' . __LINE__ . '; Got error ' . $this->Error . "\n", 3, $this->LogFile); } return array(false, $this->Error); } $response = $this->_get_response(); if ($this->Debug) { error_log('Line ' . __LINE__ . '; Got response ' . $response . "\n", 3, $this->LogFile); } $responsecode = substr($response, 0, 3); if ($responsecode != '250') { $this->ErrorCode = $responsecode; $this->Error = $response; $this->_Close_Smtp_Connection(); if ($this->Debug) { error_log('Line ' . __LINE__ . '; Got error ' . $this->Error . "\n", 3, $this->LogFile); } return array(false, $this->Error); } $data = "DATA"; if ($this->Debug) { error_log('Line ' . __LINE__ . '; Trying to put ' . $data . "\n", 3, $this->LogFile); } if (!$this->_Put_Smtp_Connection($data)) { $this->ErrorCode = 12; $this->Error = 'Unable to set data.'; $this->_Close_Smtp_Connection(); if ($this->Debug) { error_log('Line ' . __LINE__ . '; Got error ' . $this->Error . "\n", 3, $this->LogFile); } return array(false, $this->Error); } $response = $this->_get_response(); if ($this->Debug) { error_log('Line ' . __LINE__ . '; Got response ' . $response . "\n", 3, $this->LogFile); } $responsecode = substr($response, 0, 3); if ($responsecode != '354') { $this->ErrorCode = $responsecode; $this->Error = $response; $this->_Close_Smtp_Connection(); if ($this->Debug) { error_log('Line ' . __LINE__ . '; Got error ' . $this->Error . "\n", 3, $this->LogFile); } return array(false, $this->Error); } $msg = "To: " . $to . $this->_smtp_newline . "Subject: " . $subject . $this->_smtp_newline . $headers . $this->_smtp_newline . $body; $msg = str_replace("\r\n","\n",$msg); $msg = str_replace("\r","\n",$msg); $lines = explode("\n",$msg); foreach($lines as $no => $line) { // we need to rtrim here so we don't get rid of tabs before the start of the line. // the tab is extremely important for boundaries (eg sending multipart + attachment) // so it needs to stay. $data = rtrim($line); if ($this->Debug) { error_log('Line ' . __LINE__ . '; Trying to put ' . $data . "\n", 3, $this->LogFile); } if (!$this->_Put_Smtp_Connection($data)) { $this->ErrorCode = 13; $this->Error = 'Unable to send data.'; $this->_Close_Smtp_Connection(); if ($this->Debug) { error_log('Line ' . __LINE__ . '; Got error ' . $this->Error . "\n", 3, $this->LogFile); } return array(false, $this->Error); } } $data = $this->_smtp_newline . "."; if ($this->Debug) { error_log('Line ' . __LINE__ . '; Trying to put ' . $data . "\n", 3, $this->LogFile); } if (!$this->_Put_Smtp_Connection($data)) { $this->ErrorCode = 14; $this->Error = 'Unable to send "." to server.'; $this->_Close_Smtp_Connection(); if ($this->Debug) { error_log('Line ' . __LINE__ . '; Got error ' . $this->Error . "\n", 3, $this->LogFile); } return array(false, $this->Error); } $response = $this->_get_response(); if ($this->Debug) { error_log('Line ' . __LINE__ . '; Got response ' . $response . "\n", 3, $this->LogFile); } $responsecode = substr($response, 0, 3); if ($responsecode != '250') { $this->ErrorCode = $responsecode; $this->Error = $response; $this->_Close_Smtp_Connection(); if ($this->Debug) { error_log('Line ' . __LINE__ . '; Got error ' . $this->Error . "\n", 3, $this->LogFile); } return array(false, $this->Error); } if ($this->Debug) { error_log('Line ' . __LINE__ . '; Mail accepted ' . "\n", 3, $this->LogFile); } $this->_smtp_email_count++; return array(true, false); } function _Put_Smtp_Connection($data='', $connection=null) { $data .= $this->_smtp_newline; if (is_null($connection)) { $connection = $this->_smtp_connection; } $returnvalue = fputs($connection, $data, strlen($data)); return $returnvalue; } function _Get_Smtp_Connection() { if ($this->_smtp_email_count > $this->_smtp_max_email_count) { $this->_Close_Smtp_Connection(); $this->_smtp_email_count = 0; } if (!is_null($this->_smtp_connection)) { return $this->_smtp_connection; } $server = $this->SMTPServer; $username = $this->SMTPUsername; $password = $this->SMTPPassword; $port = (int)$this->SMTPPort; if ($port <= 0) { $port = 25; } $timeout = 20; $socket = @fsockopen($server, $port, $errno, $errstr, $timeout); if (!$socket) { $this->ErrorCode = 1; $this->Error = sprintf('Unable to connect to mail server: %s', $errstr . '(' . $errno . ')'); return false; } $response = $this->_get_response($socket); if ($this->Debug) { error_log('Line ' . __LINE__ . '; Got response ' . $response . "\n", 3, $this->LogFile); } $responsecode = substr($response, 0, 3); if ($responsecode != '220') { $this->ErrorCode = $responsecode; $this->Error = $response; fclose($socket); return false; } // say hi! $server = 'localhost'; $data = 'EHLO ' . $server; if ($this->Debug) { error_log('Line ' . __LINE__ . '; Trying to put ' . $data . "\n", 3, $this->LogFile); } if (!$this->_Put_Smtp_Connection($data, $socket)) { $this->ErrorCode = 2; $this->Error = 'Unable to send "EHLO" command.'; fclose($socket); if ($this->Debug) { error_log('Line ' . __LINE__ . '; Got error ' . $this->Error . "\n", 3, $this->LogFile); } return false; } $hasauthentication = false; $response = $this->_get_response($socket); $responses = explode($this->_smtp_newline, $response); foreach($responses as $line) { if (preg_match('%250[\s|-]auth(.*?)login%i', $line)) { $hasauthentication = true; break; } } if ($hasauthentication && $username) { if (!$password) { $this->ErrorCode = 3; $this->Error = 'Unable To Connect To Mail Server - It Requires Authentication'; fclose($socket); if ($this->Debug) { error_log('Line ' . __LINE__ . '; Got error ' . $this->Error . "\n", 3, $this->LogFile); } return false; } $data = "AUTH LOGIN"; if ($this->Debug) { error_log('Line ' . __LINE__ . '; Trying to put ' . $data . "\n", 3, $this->LogFile); } if (!$this->_Put_Smtp_Connection($data, $socket)) { $this->ErrorCode = 4; $this->Error = 'Unable To Connect To Mail Server - Auth Login Not Accepted'; fclose($socket); if ($this->Debug) { error_log('Line ' . __LINE__ . '; Got error ' . $this->Error . "\n", 3, $this->LogFile); } return false; } $response = $this->_get_response($socket); if ($this->Debug) { error_log('Line ' . __LINE__ . '; Got response ' . $response . "\n", 3, $this->LogFile); } $responsecode = substr($response, 0, 3); if ($responsecode != '334') { $this->ErrorCode = 5; $this->Error = 'Unable To Connect To Mail Server - Auth Login Not Supported'; fclose($socket); if ($this->Debug) { error_log('Line ' . __LINE__ . '; Got error ' . $this->Error . "\n", 3, $this->LogFile); } return false; } $data = base64_encode($username); if ($this->Debug) { error_log('Line ' . __LINE__ . '; Trying to put ' . $data . "\n", 3, $this->LogFile); } if (!$this->_Put_Smtp_Connection($data, $socket)) { $this->ErrorCode = 6; $this->Error = 'Unable To Connect To Mail Server - Username Not Written'; fclose($socket); if ($this->Debug) { error_log('Line ' . __LINE__ . '; Got error ' . $this->Error . "\n", 3, $this->LogFile); } return false; } $response = $this->_get_response($socket); if ($this->Debug) { error_log('Line ' . __LINE__ . '; Got response ' . $response . "\n", 3, $this->LogFile); } $responsecode = substr($response, 0, 3); if ($responsecode != '334') { $this->ErrorCode = $responsecode; $this->Error = $response; fclose($socket); if ($this->Debug) { error_log('Line ' . __LINE__ . '; Got error ' . $this->Error . "\n", 3, $this->LogFile); } return false; } $data = base64_encode($password); if ($this->Debug) { error_log('Line ' . __LINE__ . '; Trying to put ' . $data . "\n", 3, $this->LogFile); } if (!$this->_Put_Smtp_Connection($data, $socket)) { $this->ErrorCode = 7; $this->Error = 'Unable To Connect To Mail Server - Password Not Written'; fclose($socket); if ($this->Debug) { error_log('Line ' . __LINE__ . '; Got error ' . $this->Error . "\n", 3, $this->LogFile); } return false; } $response = $this->_get_response($socket); if ($this->Debug) { error_log('Line ' . __LINE__ . '; Got response ' . $response . "\n", 3, $this->LogFile); } $responsecode = substr($response, 0, 3); if ($responsecode != '235') { $this->ErrorCode = $responsecode; $this->Error = $response; fclose($socket); if ($this->Debug) { error_log('Line ' . __LINE__ . '; Got error ' . $this->Error . "\n", 3, $this->LogFile); } return false; } } $this->_smtp_connection = $socket; return $this->_smtp_connection; } function _Close_Smtp_Connection() { if (is_null($this->_smtp_connection)) { return; } $this->_Put_Smtp_Connection('QUIT'); fclose($this->_smtp_connection); $this->_smtp_connection = null; } function _get_response($connection=null) { if (is_null($connection)) { $connection = $this->_smtp_connection; } if (is_null($connection)) { return; } $data = ""; while($str = fgets($connection,515)) { $data .= $str; # if the 4th character is a space then we are done reading # so just break the loop if(substr($str,3,1) == " " || $str == "") { break; } } return trim($data); } /** * _JoinBody * Returns the body with the correct content type, character set, encoding and boundaries set up. * * @param string $type * * @see _GetBoundary * @see CharSet * @see ContentEncoding * @see body * * @return string The body with the content type, character set, encoding and boundaries set up. */ function _JoinBody($type='') { $type = strtolower($type); $content_type = ($type == 'h') ? 'text/html' : 'text/plain'; $body = ''; $body .= $this->_GetBoundary() . $this->_newline; $body .= 'Content-Type: ' . $content_type . '; charset="' . $this->CharSet . '"' . $this->_newline; $body .= 'Content-Transfer-Encoding: ' . $this->ContentEncoding . $this->_newline . $this->_newline; $this->_ChangePlaceholders(); $body .= $this->body[substr($type, 0, 1)]; $body .= $this->_newline . $this->_newline; return $body; } function _ChangePlaceholders() { if (!preg_match('//i', $this->body['h'])) { $this->body['h'] = str_replace('%BASIC:ARCHIVELINK%', '%BASIC:ARCHIVELINK%', $this->body['h']); } if (!preg_match('//i', $this->body['h'])) { $this->body['h'] = str_replace('%BASIC:CONFIRMLINK%', '%BASIC:CONFIRMLINK%', $this->body['h']); } if (!preg_match('//i', $this->body['h'])) { $this->body['h'] = str_replace('%BASIC:UNSUBLINK%', '%BASIC:UNSUBLINK%', $this->body['h']); } if (!preg_match('//i', $this->body['h'])) { $this->body['h'] = preg_replace('/%BASIC:MODIFYDETAILS_(.*?)%/', '%BASIC:MODIFYDETAILS_\\1%', $this->body['h']); } } /** * _JoinAttachments * Returns a string of the attachments encoded and ready to go with the email. * * @see _Attachments * @see _Boundary * @see _newline * * @return string The attachments encoded and ready to go with the email. */ function _JoinAttachments() { if (empty($this->_Attachments)) return; $body = ''; foreach($this->_Attachments as $p => $attachment) { $body .= $this->_Boundary . $this->_newline; $body .= 'Content-Type: application/octet-stream;'; if ($attachment['name']) $body .= ' name="' . $attachment['name'] . '"'; $body .= $this->_newline; $body .= 'Content-Transfer-Encoding: base64' . $this->_newline; $body .= 'Content-Disposition: attachment;'; $body .= ' filename="' . (($attachment['name']) ? $attachment['name'] : basename($attachment['path'])) . '"' . $this->_newline . $this->_newline; $fp = fopen($attachment['path'], 'rb'); $filedata = fread($fp, filesize($attachment['path'])); fclose($fp); $body .= chunk_split(base64_encode($filedata)) . $this->_newline . $this->_newline; unset($filedata); unset($fp); } $body .= $this->_Boundary . '--' . $this->_newline . $this->_newline; return $body; } function SetSmtp($servername=false, $username=false, $password=false, $port=25) { if (!$servername) { $this->SMTPServer = false; $this->SMTPUsername = false; $this->SMTPPassword = false; $this->SMTPPort = 25; return true; } $this->SMTPServer = $servername; $this->SMTPUsername = $username; $this->SMTPPassword = $password; $this->SMTPPort = (int)$port; return true; } // h = html, t = text. function SetSubscriberFormat($format='h') { $this->SendFormat = strtolower($format); } /** * ForceLinkChecks * Whether to force checking of links or not. This is off by default so you can send regular emails without trying to add unsubscribe or modify details links. * * @param bool Whether to check the links or not. * * @see forcechecks * * @return void Sets the class var, doesn't return anything. */ function ForceLinkChecks($forcechecks=false) { $this->forcechecks = (bool)$forcechecks; } /** * TrackLinks * Whether to track links or not. This is off by default. * * @param bool Whether to track links or not. * * @see checklinks * * @return void Sets the class var, doesn't return anything. */ function TrackLinks($checklinks=false) { $this->checklinks = (bool)$checklinks; } /** * TrackOpens * Whether to track email opens or not. This is off by default. * * @param bool Whether to track opens or not. * * @see trackopens * * @return void Sets the class var, doesn't return anything. */ function TrackOpens($trackopens=false) { $this->trackopens = (bool)$trackopens; } function ForgetEmail() { $this->body['t'] = null; $this->body['h'] = null; $this->AssembledEmail = array( 'Headers' => array('multipart' => null, 'h' => null, 't' => null), 'Body' => array('multipart' => null, 'h' => null, 't' => null), 'Subject' => null ); $this->_FoundLinks['t'] = array(); $this->_FoundLinks['h'] = array(); $this->_convertedlinks = array(); $this->ForceLinkChecks(false); $this->TrackLinks(false); $this->TrackOpens(false); $this->SentBy = false; $this->SetSmtp(false); $this->_sendmailparameters = null; } function DisableUnsubscribe($disable=true) { $this->disableunsubcribe = (bool)$disable; } function SaveLink($url='', $type='send') { $type = strtolower($type); $url = str_replace(array('"', "'"), '', $url); $qry = "SELECT linkid FROM " . $this->TablePrefix . "links WHERE URL='" . mysql_escape_string($url) . "' AND ComposedID='" . (int)$this->ComposedID . "' AND LinkType='" . mysql_escape_string($type) . "'"; $result = mysql_query($qry); if (mysql_num_rows($result) > 0) { $linkid = mysql_result($result, 0, 0); } else { $qry = "INSERT INTO " . $this->TablePrefix . "links (URL, ComposedID, LinkType, AdminID) VALUES('" . mysql_escape_string($url) . "', '" .(int)$this->ComposedID . "', '" . mysql_escape_string($type) . "', '" . mysql_escape_string($this->AdminID) . "')"; mysql_query($qry); $linkid = mysql_insert_id(); } mysql_free_result($result); return $linkid; } } if( !function_exists( 'html_entity_decode' ) ) { function html_entity_decode( $given_html, $quote_style = ENT_QUOTES ) { $trans_table = array_flip(get_html_translation_table( HTML_SPECIALCHARS, $quote_style )); $trans_table['''] = "'"; return ( strtr( $given_html, $trans_table ) ); } } ?>