/** * Show_Send_Step_4 * Step 4 handles two pieces of functionality: * - if cron support is enabled, it "approves" the job for sending and then redirects the user to the main splittest page * * If cron is not enabled, it processes and sends the emails out in popup mode. * It looks at the queues table for people to send to, and sends one email per window refresh. * It prints out a report of what's going on: * - how many have been sent * - how many left * - approx how long it has taken so far * - approx how long to go * - optional extra - pause after displaying that info and sending the email (based on user restrictions) * * @uses Jobs_API * @uses Jobs_API::ApproveJob * @uses Jobs_API::QueueSize * @uses CheckCronEnabled * @uses Splittest_Send_API::StartJob */ public function Show_Send_Step_4() { $send_details = IEM::sessionGet('SplitTestSendDetails'); if (!$send_details || !isset($send_details['splitid']) || (int) $send_details['splitid'] <= 0) { FlashMessage(GetLang('Addon_splittest_Send_InvalidSplitTest'), SS_FLASH_MSG_ERROR, $this->admin_url); return; } $jobid = $send_details['Job']; require_once SENDSTUDIO_API_DIRECTORY . '/jobs.php'; $jobApi = new Jobs_API(); if (isset($_GET['Start']) || self::CheckCronEnabled()) { /** * Remove the "cleanup" variables so we don't kill the send off when we either * - successfully schedule a send * - or start a send going. */ IEM::sessionRemove('SplitTestSend_Cleanup'); $user = GetUser(); $jobApi->ApproveJob($jobid, $user->Get('userid'), $user->Get('userid')); } /** * If we get here and cron is enabled, we're finishing off a scheduled send setup. * Show a message and return the user to the manage screen. */ if (self::CheckCronEnabled()) { FlashMessage(GetLang('Addon_splittest_Send_JobScheduled'), SS_FLASH_MSG_SUCCESS, $this->admin_url); return; } $this->template_system->Assign('AdminUrl', $this->admin_url, false); $send_api = $this->GetApi('Splittest_Send'); if (isset($_GET['Start'])) { $send_api->StartJob($jobid, $send_details['splitid']); } $sendqueue = $jobApi->GetJobQueue($jobid); $job = $jobApi->LoadJob($jobid); $send_api->Set('statids', $send_details['Stats']); $send_api->Set('jobdetails', $job['jobdetails']); $send_api->Set('jobowner', $job['ownerid']); $queuesize = $jobApi->QueueSize($sendqueue, 'splittest'); $send_details['SendQueue'] = $sendqueue; $timenow = $send_api->GetServerTime(); $timediff = $timenow - $send_details['SendStartTime']; $time_so_far = $this->TimeDifference($timediff); $num_left_to_send = $send_details['SendSize'] - $queuesize; if ($num_left_to_send > 0) { $timeunits = $timediff / $num_left_to_send; $timediff = $timeunits * $queuesize; } else { $timediff = 0; } $timewaiting = $this->TimeDifference($timediff); $this->template_system->Assign('SendTimeSoFar', sprintf(GetLang('Addon_splittest_Send_Step4_TimeSoFar'), $time_so_far)); $this->template_system->Assign('SendTimeLeft', sprintf(GetLang('Addon_splittest_Send_Step4_TimeLeft'), $timewaiting)); if ($num_left_to_send == 1) { $this->template_system->Assign('Send_NumberAlreadySent', GetLang('Addon_splittest_Send_Step4_NumberSent_One')); } else { $this->template_system->Assign('Send_NumberAlreadySent', sprintf(GetLang('Addon_splittest_Send_Step4_NumberSent_Many'), $this->PrintNumber($num_left_to_send))); } if ($queuesize <= 0) { require_once SENDSTUDIO_API_DIRECTORY . '/ss_email.php'; $email = new SS_Email_API(); if (SENDSTUDIO_SAFE_MODE) { $email->Set('imagedir', TEMP_DIRECTORY . '/send'); } else { $email->Set('imagedir', TEMP_DIRECTORY . '/send.' . $jobid . '.' . $sendqueue); } $email->CleanupImages(); $send_details['SendEndTime'] = $send_api->GetServerTime(); IEM::sessionSet('SplitTestSendDetails', $send_details); $this->template_system->Assign('Send_NumberLeft', GetLang('Addon_splittest_Send_Step4_SendFinished')); $this->template_system->ParseTemplate('send_step4'); ?> <script> window.opener.focus(); window.opener.document.location = '<?php echo $this->admin_url . '&Action=Send&Step=5'; ?> '; window.close(); </script> <?php return; } if ($queuesize == 1) { $this->template_system->Assign('Send_NumberLeft', GetLang('Addon_splittest_Send_Step4_NumberLeft_One')); } else { $this->template_system->Assign('Send_NumberLeft', sprintf(GetLang('Addon_splittest_Send_Step4_NumberLeft_Many'), $this->PrintNumber($queuesize))); } $send_api->SetupJob($jobid, $sendqueue); $send_api->SetupNewsletter(); $recipients = $send_api->FetchFromQueue($sendqueue, 'splittest', 1, 1); $send_api->SetupDynamicContentFields($recipients); $send_api->SetupCustomFields($recipients); $sent_ok = false; foreach ($recipients as $p => $recipientid) { $send_results = $send_api->SendToRecipient($recipientid, $sendqueue); // save the info in the session, then see if we need to pause between each email. if ($send_results['success'] > 0) { $sent_ok = true; $send_details['EmailResults']['success']++; } else { $send_details['EmailResults']['failure']++; } $send_details['EmailResults']['total']++; IEM::sessionSet('SplitTestSendDetails', $send_details); } session_write_close(); $this->template_system->ParseTemplate('send_step4'); // we should only need to pause if we successfully sent. if ($sent_ok) { $send_api->Pause(); } }
/** * SetupEmail * Sets up the email object for use. * If the email has been set up before, it sets the Email_API object to the cache version and returns. * * If it has not been set up before, * the newsletter is loaded into the email class (subject, htmlbody, textbody, attachments) * * If it's a partial setup (the flag passed in), once the content has been loaded into the Email_API object * the method returns. * * This is used to get custom field id's being used in the email campaigns * so they can be loaded in bulk. * * If it's not a partial setup, then it * - sets the appropriate smtp details * - loads attachments * - sets extra header information * - sets the email header details (bounce, reply-to, from details etc) * - after all of that, set the object into the email_objects cache for later use. * * @param Boolean $partial_setup Whether this is a partial setup or not. A partial set up is used to work out which custom fields are being used so they can be loaded in bulk. * * @uses Email_API * @uses email_objects * @uses newsletters * @uses _sending_newsletter * @uses SS_Email_API */ private function SetupEmail($partial_setup = false) { if (isset($this->email_objects[$this->_sending_newsletter])) { $this->Email_API = $this->email_objects[$this->_sending_newsletter]; return; } /** * Set up the email class * so we can get the custom fields we need to. */ if (!isset($this->newsletters[$this->_sending_newsletter])) { return false; } $newsletter = $this->newsletters[$this->_sending_newsletter]; $email_api = new SS_Email_API(); if (SENDSTUDIO_SEND_TEST_MODE) { $email_api->TestMode = true; } $email_api->Set('Multipart', $this->jobdetails['Multipart']); $email_api->Set('Subject', $newsletter['Subject']); if ($this->jobdetails['Multipart']) { if ($newsletter['TextBody'] && $newsletter['HTMLBody'] && $newsletter['Format'] == 'b') { $sent_format = 'm'; } else { $email_api->Set('Multipart', false); } } if ($newsletter['TextBody'] && in_array($newsletter['Format'], array('t', 'b'))) { $email_api->AddBody('text', $newsletter['TextBody']); $email_api->AppendBody('text', $this->user->Get('textfooter')); $email_api->AppendBody('text', stripslashes(SENDSTUDIO_TEXTFOOTER)); } if ($newsletter['HTMLBody'] && in_array($newsletter['Format'], array('h', 'b'))) { $email_api->AddBody('html', $newsletter['HTMLBody']); $email_api->AppendBody('html', $this->user->Get('htmlfooter')); $email_api->AppendBody('html', stripslashes(SENDSTUDIO_HTMLFOOTER)); } if ($partial_setup) { $this->Email_API = $email_api; return; } $email_api->ClearRecipients(); $email_api->SetSmtp(SENDSTUDIO_SMTP_SERVER, SENDSTUDIO_SMTP_USERNAME, @base64_decode(SENDSTUDIO_SMTP_PASSWORD), SENDSTUDIO_SMTP_PORT); $email_api->Set('statid', $this->statids[$this->_sending_newsletter]); $email_api->Set('listids', $this->jobdetails['Lists']); if (SENDSTUDIO_FORCE_UNSUBLINK) { $email_api->ForceLinkChecks(true); } $email_api->TrackOpens(true); $email_api->TrackLinks(true); $email_api->Set('CharSet', $this->jobdetails['Charset']); if (!SENDSTUDIO_SAFE_MODE) { $email_api->Set('imagedir', TEMP_DIRECTORY . '/send.' . $this->_jobid . '.' . $this->_queueid); } else { $email_api->Set('imagedir', TEMP_DIRECTORY . '/send'); } // clear out the attachments just to be safe. $email_api->ClearAttachments(); if ($newsletter['Attachments']) { $path = $newsletter['Attachments']['path']; $files = $newsletter['Attachments']['filelist']; foreach ($files as $p => $file) { $email_api->AddAttachment($path . '/' . $file); } } $email_api->Set('FromName', $this->jobdetails['SendFromName']); $email_api->Set('FromAddress', $this->jobdetails['SendFromEmail']); $email_api->Set('ReplyTo', $this->jobdetails['ReplyToEmail']); $email_api->Set('BounceAddress', $this->jobdetails['BounceEmail']); $email_api->Set('EmbedImages', $this->jobdetails['EmbedImages']); $email_api->Set('SentBy', $this->user->Get('userid')); if ($this->user->smtpserver) { $email_api->SetSmtp($this->user->smtpserver, $this->user->smtpusername, $this->user->smtppassword, $this->user->smtpport); } $this->email_objects[$this->_sending_newsletter] = $email_api; $this->Email_API = $email_api; }
/** * _send * * Send email campaign that is triggered by the "trigger email". * * @param Array $triggerrecord Trigger record * @param Array $queuerecord Queue record * @param Array $newsletter Newsletter record * @return Array Returns a status result that contains the sending result, and the email address that get sent */ private function _send($triggerrecord, $queuerecord, $newsletter) { static $prevUserID = 0; static $prevQueueID = 0; static $userPause = 0; static $subscriberAPI = null; $triggerid = $triggerrecord['triggeremailsid']; $newsletterid = $newsletter['newsletterid']; $recipientid = $queuerecord['recipient']; $user = null; $email = null; $customfields = array(); $return = array( 'email' => '', 'message' => '', 'listid' => 0, 'result' => false ); if (is_null($subscriberAPI)) { $subscriberAPI = new Subscribers_API(); } /** * Get owner of trigger email */ $user = $this->_cacheUser($triggerrecord['ownerid']); if (empty($user)) { trigger_error('Cannot get trigger owner record', E_USER_NOTICE); return $return; } /** * ----- */ /** * Get email object, and setup * This will setup emails and setup everything that it needs to have according to the newsletter record. */ $email = new SS_Email_API(); $email->Set('CharSet', SENDSTUDIO_CHARSET); if (!SENDSTUDIO_SAFE_MODE) { $email->Set('imagedir', TEMP_DIRECTORY . '/triggeremails.' . $triggerrecord['queueid']); } else { $email->Set('imagedir', TEMP_DIRECTORY . '/send'); } if (SENDSTUDIO_FORCE_UNSUBLINK) { $email->ForceLinkChecks(true); } $email->Set('Subject', $newsletter['subject']); /** * Setup attachments */ $email->ClearAttachments(); $tempAttachments = SendStudio_Functions::GetAttachments('newsletters', $newsletterid, true); if ($tempAttachments) { $path = $tempAttachments['path']; $files = $tempAttachments['filelist']; foreach ($files as $p => $file) { $email->AddAttachment($path . DIRECTORY_SEPARATOR . $file); } } /** * ----- */ /** * Set up the contents of the newsletter and the formatting (ie. multipart/html only/text only) */ $format = $newsletter['format']; $email->Set('Multipart', false); if ($format == 'b' || $format == 't') { if ($newsletter['textbody']) { $email->AddBody('text', $newsletter['textbody']); $email->AppendBody('text', $user->Get('textfooter')); $email->AppendBody('text', stripslashes(SENDSTUDIO_TEXTFOOTER)); } } if ($format == 'b' || $format == 'h') { if ($newsletter['htmlbody']) { $email->AddBody('html', $newsletter['htmlbody']); $email->AppendBody('html', $user->Get('htmlfooter')); $email->AppendBody('html', stripslashes(SENDSTUDIO_HTMLFOOTER)); } } if ($format == 'b') { if ($newsletter['textbody'] && $newsletter['htmlbody']) { $email->Set('Multipart', true); } else { $email->Set('Multipart', false); } } /** * ----- */ // Setup custom fields $customfields = $email->GetCustomFields(); if (!is_a($email, 'SS_Email_API')) { trigger_error('Cannot instantiate email object to be used to send emails', E_USER_NOTICE); return $return; } $email->Debug = $this->_debugMode; /** * ----- */ /** * Set up email object for any headers and SMTP server details. * These setup will take account of each trigger records (ie. owner and user as well as stats and other sending related headers) */ /** * Calculate pause time to make sure it complies with the throttling */ $pause = $pausetime = 0; if ($user->perhour > 0) { $pause = $user->perhour; } // in case the system rate is less than the user rate, lower it. if (SENDSTUDIO_MAXHOURLYRATE > 0) { if ($pause == 0) { $pause = SENDSTUDIO_MAXHOURLYRATE; } else { $pause = min($pause, SENDSTUDIO_MAXHOURLYRATE); } } if ($pause > 0) { $pausetime = 3600 / $pause; } $userPause = $pausetime; $this->_log('UserPause is set to ' . $pausetime); /** * ----- */ $email->SetSmtp(SENDSTUDIO_SMTP_SERVER, SENDSTUDIO_SMTP_USERNAME, @base64_decode(SENDSTUDIO_SMTP_PASSWORD), SENDSTUDIO_SMTP_PORT); if ($user->smtpserver) { $email->SetSmtp($user->smtpserver, $user->smtpusername, $user->smtppassword, $user->smtpport); } // If queue has changed since previous send, update email class for queue related information $email->TrackOpens((array_key_exists('trackopens', $triggerrecord['triggeractions']['send']) && $triggerrecord['triggeractions']['send']['trackopens'] == '1')); $email->TrackLinks((array_key_exists('tracklinks', $triggerrecord['triggeractions']['send']) && $triggerrecord['triggeractions']['send']['tracklinks'] == '1')); $email->Set('statid', $triggerrecord['statid']); $email->Set('FromName', $triggerrecord['triggeractions']['send']['sendfromname']); $email->Set('FromAddress', $triggerrecord['triggeractions']['send']['sendfromemail']); $email->Set('ReplyTo', $triggerrecord['triggeractions']['send']['replyemail']); $email->Set('BounceAddress', $triggerrecord['triggeractions']['send']['bounceemail']); $email->Set('EmbedImages', ((array_key_exists('embedimages', $triggerrecord['triggeractions']['send'])) && $triggerrecord['triggeractions']['send']['embedimages'] == '1')); $email->Set('Multipart', ((array_key_exists('multipart', $triggerrecord['triggeractions']['send'])) && $triggerrecord['triggeractions']['send']['multipart'] == '1')); /** * ----- */ /** * Set up recipient */ $subscriberinfo = $subscriberAPI->LoadSubscriberList($recipientid, 0, true); if (empty($subscriberinfo)) { trigger_error('Cannot fetch recipient details', E_USER_NOTICE); return $return; } $listinfo = $this->_cacheListGet($subscriberinfo['listid']); if (empty($listinfo)) { trigger_error('Unable to load recipient list details', E_USER_NOTICE); return $return; } // List ID for the particualar subscriber $email->Set('listids', $subscriberinfo['listid']); $subscriberinfo['ipaddress'] = $subscriberinfo['confirmip']; if (!$subscriberinfo['ipaddress']) { $subscriberinfo['ipaddress'] = $subscriberinfo['requestip']; } if (!$subscriberinfo['ipaddress']) { $subscriberinfo['ipaddress'] = ''; } $subscriberinfo['subscriberid'] = $recipientid; $subscriberinfo['newsletter'] = $triggerrecord['triggeractions']['send']['newsletterid']; $subscriberinfo['listid'] = $subscriberinfo['listid']; $subscriberinfo['statid'] = $triggerrecord['statid']; $subscriberinfo['listname'] = $listinfo['name']; $subscriberinfo['companyname'] = $listinfo['companyname']; $subscriberinfo['companyaddress'] = $listinfo['companyaddress']; $subscriberinfo['companyphone'] = $listinfo['companyphone']; if (!isset($subscriberinfo['CustomFields']) && empty($subscriberinfo['CustomFields'])) { $subscriberinfo['CustomFields'] = array(); /** * If the subscriber has no custom fields coming from the database, then set up blank placeholders. * If they have no custom fields in the database, they have no records in the 'all_customfields' array - so we need to fill it up with blank entries. */ foreach ($customfields as $fieldid => $fieldname) { $subscriberinfo['CustomFields'][] = array( 'fieldid' => $fieldid, 'fieldname' => $fieldname, 'fieldtype' => 'text', 'defaultvalue' => '', 'fieldsettings' => '', 'subscriberid' => $recipientid, 'data' => '' ); } } else { require_once(SENDSTUDIO_API_DIRECTORY.'/customfields_date.php'); foreach($subscriberinfo['CustomFields'] as $ar_key => $ar_value){ if($ar_value['fieldtype'] == 'date'){ $cfdateapi = new CustomFields_Date_API($ar_value['fieldid']); $real_order = $cfdateapi->GetRealValue($ar_value['data']); $subscriberinfo['CustomFields'][$ar_key]['data'] = $real_order; } } } // TODO refactor $name = ''; $firstname_field = $triggerrecord['triggeractions']['send']['firstnamefield']; if ($firstname_field) { foreach ($subscriberinfo['CustomFields'] as $p => $details) { if ($details['fieldid'] == $firstname_field && $details['data'] != '') { $name = $details['data']; break; } } } $lastname_field = $triggerrecord['triggeractions']['send']['lastnamefield']; if ($lastname_field) { foreach ($subscriberinfo['CustomFields'] as $p => $details) { if ($details['fieldid'] == $lastname_field && $details['data'] != '') { $name .= ' ' . $details['data']; break; } } } if (trim($name) == '') { $name = false; } // -- // SetupDynamicContentFields $dctEventListId = (is_array($subscriberinfo['listid']))?$subscriberinfo['listid']:array($subscriberinfo['listid']); $dctEvent =new EventData_IEM_ADDON_DYNAMICCONTENTTAGS_REPLACETAGCONTENT(); $dctEvent->lists = $dctEventListId; $dctEvent->info = array($subscriberinfo); $dctEvent->trigger(); // -- $email->ClearRecipients(); $email->AddRecipient($subscriberinfo['emailaddress'], $name, $subscriberinfo['format'], $subscriberinfo['subscriberid']); $email->AddDynamicContentInfo($dctEvent->contentTobeReplaced); $email->AddCustomFieldInfo($subscriberinfo['emailaddress'], $subscriberinfo); $status = $email->Send(true, true); if (!$status['success']) { list($return['email'], $return['message']) = $status['fail'][0]; trigger_error("Failed sending trigger email to {$return['email']}: {$return['message']}"); return $return; } $return['listid'] = $subscriberinfo['listid']; $return['email'] = $subscriberinfo['emailaddress']; /** * ----- */ // Set previous user $prevUserID = $user->userid; // Set previous queue $prevQueueID = $triggerrecord['queueid']; $return['result'] = true; return $return; }
/** * NotifyOwner * This will notify the list owner(s) of job runs. * This will send the appropriate message depending on the state of the job. * If the job is not set to notify the owner, this does nothing. * * @see emailssent * @see jobdetails * @see jobstatus * @see Email_API::ForgetEmail * @see GetUser * @see Email_API::Set * @see Email_API::Subject * @see Email_API::FromName * @see Email_API::FromAddress * @see Email_API::Multipart * @see Email_API::AddBody * @see Email_API::ClearAttachments * @see Email_API::ClearRecipients * @see Email_API::AddRecipient * @see Email_API::Send * @see Sendstudio_Functions::PrintTime * @see Sendstudio_Functions::FormatNumber * * @return Void Doesn't return anything. */ function NotifyOwner() { if (empty($this->jobdetails)) { return; } if (!$this->jobdetails['NotifyOwner']) { return; } if (is_null($this->jobstatus)) { return; } /** * If test mode is enabled, no point doing anything else. */ if (SENDSTUDIO_SEND_TEST_MODE) { return; } if (!class_exists('SS_Email_API', false)) { require_once SENDSTUDIO_API_DIRECTORY . DIRECTORY_SEPARATOR . 'ss_email.php'; } $notify_email = new SS_Email_API; $owner = GetUser($this->jobowner); // Check if each user have SMTP settings specified. // Otherwise use the global SMTP settings. if ($owner->smtpserver) { $notify_email->SetSmtp($owner->smtpserver, $owner->smtpusername, $owner->smtppassword, $owner->smtpport); } else { $notify_email->SetSmtp(SENDSTUDIO_SMTP_SERVER, SENDSTUDIO_SMTP_USERNAME, @base64_decode(SENDSTUDIO_SMTP_PASSWORD), SENDSTUDIO_SMTP_PORT); } $time = $this->sendstudio_functions->PrintTime(); /** * If the notify email subject or message are empty, create them. * This is mainly for backwards compatibility so the jobs_send.php file didn't need to be changed too much. */ if ($this->notify_email['subject'] == '' || $this->notify_email['message'] == '') { switch ($this->jobstatus) { case 'c': $subject = sprintf(GetLang('Job_Subject_Complete'), $this->newsletter['Subject']); if ($this->emailssent == 1) { $message = sprintf(GetLang('Job_Message_Complete_One'), $this->newsletter['Subject'], $time); } else { $message = sprintf(GetLang('Job_Message_Complete_Many'), $this->newsletter['Subject'], $time, $this->sendstudio_functions->FormatNumber($this->emailssent)); } break; case 'p': $subject = sprintf(GetLang('Job_Subject_Paused'), $this->newsletter['Subject']); if ($this->emailssent == 1) { $message = sprintf(GetLang('Job_Message_Paused_One'), $this->newsletter['Subject'], $time); } else { $message = sprintf(GetLang('Job_Message_Paused_Many'), $this->newsletter['Subject'], $time, $this->sendstudio_functions->FormatNumber($this->emailssent)); } break; default: $subject = sprintf(GetLang('Job_Subject_Started'), $this->newsletter['Subject']); $message = sprintf(GetLang('Job_Message_Started'), $this->newsletter['Subject'], $time); } $this->notify_email = array ( 'subject' => $subject, 'message' => $message ); } $subject = $this->notify_email['subject']; $message = $this->notify_email['message']; $notify_email->Set('Subject', $subject); $notify_email->Set('CharSet', SENDSTUDIO_CHARSET); if ($owner->fullname) { $notify_email->Set('FromName', $owner->fullname); } else { $notify_email->Set('FromName', GetLang('SendingSystem')); } if ($owner->emailaddress) { $notify_email->Set('FromAddress', $owner->emailaddress); } else { $notify_email->Set('FromAddress', GetLang('SendingSystem_From')); } $notify_email->Set('Multipart', false); $notify_email->AddBody('text', $message); $query = "SELECT listid, ownername, owneremail FROM " . SENDSTUDIO_TABLEPREFIX . "lists WHERE listid IN(" . implode(',', $this->jobdetails['Lists']) . ")"; $result = $this->Db->Query($query); while ($row = $this->Db->Fetch($result)) { $notify_email->AddRecipient($row['owneremail'], $row['ownername'], 't'); } $notify_email->Send(); $notify_email->ForgetEmail(); unset($notify_email); $this->notify_email['subject'] = ''; $this->notify_email['message'] = ''; }