2 if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
3 /*********************************************************************************
4 * SugarCRM Community Edition is a customer relationship management program developed by
5 * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
7 * This program is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU Affero General Public License version 3 as published by the
9 * Free Software Foundation with the addition of the following permission added
10 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
11 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
12 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
19 * You should have received a copy of the GNU Affero General Public License along with
20 * this program; if not, see http://www.gnu.org/licenses or write to the Free
21 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
25 * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
27 * The interactive user interfaces in modified source and object code versions
28 * of this program must display Appropriate Legal Notices, as required under
29 * Section 5 of the GNU Affero General Public License version 3.
31 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
32 * these Appropriate Legal Notices must retain the display of the "Powered by
33 * SugarCRM" logo. If the display of the logo is not reasonably feasible for
34 * technical reasons, the Appropriate Legal Notices must display the words
35 * "Powered by SugarCRM".
36 ********************************************************************************/
40 class EmailMan extends SugarBean{
58 var $table_name = "emailman";
59 var $object_name = "EmailMan";
60 var $module_dir = "EmailMan";
65 var $notes_array = array();
66 var $verified_email_marketing_ids = array();
68 return "EmailMan:\nid = $this->id ,user_id= $this->user_id module = $this->module , related_id = $this->related_id , related_type = $this->related_type ,list_id = $this->list_id, send_date_time= $this->send_date_time\n";
71 // This is used to retrieve related fields from form posts.
72 var $additional_column_fields = array();
79 var $new_schema = true;
81 function create_new_list_query($order_by, $where,$filter=array(),$params=array(), $show_deleted = 0,$join_type='', $return_array = false,$parentbean=null, $singleSelect = false) {
82 $query = array('select' => '', 'from' => '', 'where' => '', 'order_by' => '');
86 $query['select'] = "SELECT $this->table_name.* ,
87 campaigns.name as campaign_name,
88 email_marketing.name as message_name,
90 WHEN 'Contacts' THEN ".$this->db->concat('contacts', array('first_name', 'last_name'), ' ')."
91 WHEN 'Leads' THEN ".$this->db->concat('leads', array('first_name', 'last_name'), ' ')."
92 WHEN 'Accounts' THEN accounts.name
93 WHEN 'Users' THEN ".$this->db->concat('users', array('first_name', 'last_name'), ' ')."
94 WHEN 'Prospects' THEN ".$this->db->concat('prospects', array('first_name', 'last_name'), ' ')."
96 $query['from'] = " FROM $this->table_name
97 LEFT JOIN users ON users.id = $this->table_name.related_id and $this->table_name.related_type ='Users'
98 LEFT JOIN contacts ON contacts.id = $this->table_name.related_id and $this->table_name.related_type ='Contacts'
99 LEFT JOIN leads ON leads.id = $this->table_name.related_id and $this->table_name.related_type ='Leads'
100 LEFT JOIN accounts ON accounts.id = $this->table_name.related_id and $this->table_name.related_type ='Accounts'
101 LEFT JOIN prospects ON prospects.id = $this->table_name.related_id and $this->table_name.related_type ='Prospects'
102 LEFT JOIN prospect_lists ON prospect_lists.id = $this->table_name.list_id
103 LEFT JOIN email_addr_bean_rel ON email_addr_bean_rel.bean_id = $this->table_name.related_id and $this->table_name.related_type = email_addr_bean_rel.bean_module and email_addr_bean_rel.primary_address = 1 and email_addr_bean_rel.deleted=0
104 LEFT JOIN campaigns ON campaigns.id = $this->table_name.campaign_id
105 LEFT JOIN email_marketing ON email_marketing.id = $this->table_name.marketing_id ";
107 $where_auto = " $this->table_name.deleted=0";
110 $query['where'] = "WHERE $where AND ".$where_auto;
112 $query['where'] = "WHERE ".$where_auto;
114 if(isset($params['group_by'])) {
115 $query['order_by'] .= " GROUP BY {$params['group_by']}";
120 $query['order_by'] = ' ORDER BY ' . $this->process_order_by($order_by, null);
127 return $query['select'] . $query['from'] . $query['where']. $query['order_by'];
131 function create_queue_items_query($order_by, $where,$filter=array(),$params=array(), $show_deleted = 0,$join_type='', $return_array = false,$parentbean=null, $singleSelect = false) {
134 return parent::create_new_list_query($order_by, $where,$filter,$params, $show_deleted,$join_type, $return_array,$parentbean, $singleSelect);
137 $query = "SELECT $this->table_name.* ,
138 campaigns.name as campaign_name,
139 email_marketing.name as message_name,
141 WHEN 'Contacts' THEN ".$this->db->concat('contacts', array('first_name', 'last_name'), ' ')."
142 WHEN 'Leads' THEN ".$this->db->concat('leads', array('first_name', 'last_name'), ' ')."
143 WHEN 'Accounts' THEN accounts.name
144 WHEN 'Users' THEN ".$this->db->concat('users', array('first_name', 'last_name'), ' ')."
145 WHEN 'Prospects' THEN ".$this->db->concat('prospects', array('first_name', 'last_name'), ' ')."
146 END) recipient_name";
148 $query .= " FROM $this->table_name
149 LEFT JOIN users ON users.id = $this->table_name.related_id and $this->table_name.related_type ='Users'
150 LEFT JOIN contacts ON contacts.id = $this->table_name.related_id and $this->table_name.related_type ='Contacts'
151 LEFT JOIN leads ON leads.id = $this->table_name.related_id and $this->table_name.related_type ='Leads'
152 LEFT JOIN accounts ON accounts.id = $this->table_name.related_id and $this->table_name.related_type ='Accounts'
153 LEFT JOIN prospects ON prospects.id = $this->table_name.related_id and $this->table_name.related_type ='Prospects'
154 LEFT JOIN prospect_lists ON prospect_lists.id = $this->table_name.list_id
155 LEFT JOIN email_addr_bean_rel ON email_addr_bean_rel.bean_id = $this->table_name.related_id and $this->table_name.related_type = email_addr_bean_rel.bean_module and email_addr_bean_rel.primary_address = 1 and email_addr_bean_rel.deleted=0
156 LEFT JOIN campaigns ON campaigns.id = $this->table_name.campaign_id
157 LEFT JOIN email_marketing ON email_marketing.id = $this->table_name.marketing_id ";
160 if( isset($params['group_by']) )
162 $group_by = str_replace("emailman", "em", $params['group_by']);
163 $query .= "INNER JOIN (select min(id) as id from emailman em GROUP BY $group_by ) secondary
164 on {$this->table_name}.id = secondary.id ";
167 $where_auto = " $this->table_name.deleted=0";
170 $query .= "WHERE $where AND ".$where_auto;
172 $query .= "WHERE ".$where_auto;
177 $query .= ' ORDER BY ' . $this->process_order_by($order_by, null);
184 function create_list_query($order_by, $where, $show_deleted = 0){
186 $query = "SELECT $this->table_name.* ,
187 campaigns.name as campaign_name,
188 email_marketing.name as message_name,
190 WHEN 'Contacts' THEN ".$this->db->concat('contacts', array('first_name', 'last_name'), ' ')."
191 WHEN 'Leads' THEN ".$this->db->concat('leads', array('first_name', 'last_name'), ' ')."
192 WHEN 'Accounts' THEN accounts.name
193 WHEN 'Users' THEN ".$this->db->concat('users', array('first_name', 'last_name'), ' ')."
194 WHEN 'Prospects' THEN ".$this->db->concat('prospects', array('first_name', 'last_name'), ' ')."
195 END) recipient_name";
196 $query .= " FROM $this->table_name
197 LEFT JOIN users ON users.id = $this->table_name.related_id and $this->table_name.related_type ='Users'
198 LEFT JOIN contacts ON contacts.id = $this->table_name.related_id and $this->table_name.related_type ='Contacts'
199 LEFT JOIN leads ON leads.id = $this->table_name.related_id and $this->table_name.related_type ='Leads'
200 LEFT JOIN accounts ON accounts.id = $this->table_name.related_id and $this->table_name.related_type ='Accounts'
201 LEFT JOIN prospects ON prospects.id = $this->table_name.related_id and $this->table_name.related_type ='Prospects'
202 LEFT JOIN prospect_lists ON prospect_lists.id = $this->table_name.list_id
203 LEFT JOIN email_addr_bean_rel ON email_addr_bean_rel.bean_id = $this->table_name.related_id and $this->table_name.related_type = email_addr_bean_rel.bean_module and email_addr_bean_rel.primary_address = 1 and email_addr_bean_rel.deleted=0
204 LEFT JOIN campaigns ON campaigns.id = $this->table_name.campaign_id
205 LEFT JOIN email_marketing ON email_marketing.id = $this->table_name.marketing_id ";
207 $where_auto = " $this->table_name.deleted=0";
210 $query .= "where $where AND ".$where_auto;
212 $query .= "where ".$where_auto;
216 $query .= ' ORDER BY ' . $this->process_order_by($order_by, null);
221 function get_list_view_data()
223 global $locale, $current_user;
224 $temp_array = parent::get_list_view_array();
226 $related_type = $temp_array['RELATED_TYPE'];
227 $related_id = $temp_array['RELATED_ID'];
228 $is_person = SugarModule::get($related_type)->moduleImplements('Person');
232 $query = "SELECT first_name, last_name FROM ". strtolower($related_type) ." WHERE id ='". $related_id ."'";
234 $query = "SELECT name FROM ". strtolower($related_type) ." WHERE id ='". $related_id ."'";
237 $result=$this->db->query($query);
238 $row=$this->db->fetchByAssoc($result);
242 $temp_array['RECIPIENT_NAME'] = $is_person ? $locale->getLocaleFormattedName($row['first_name'], $row['last_name'], '') : $row['name'];
245 //also store the recipient_email address
246 $query = "SELECT addr.email_address FROM email_addresses addr,email_addr_bean_rel eb WHERE eb.deleted=0 AND addr.id=eb.email_address_id AND bean_id ='". $related_id ."' AND primary_address = '1'";
248 $result=$this->db->query($query);
249 $row=$this->db->fetchByAssoc($result);
252 $temp_array['RECIPIENT_EMAIL']=$row['email_address'];
255 $this->email1 = $temp_array['RECIPIENT_EMAIL'];
256 $temp_array['EMAIL1_LINK'] = $current_user->getEmailLink('email1', $this, '', '', 'ListView');
262 function set_as_sent($email_address, $delete= true,$email_id=null, $email_type=null,$activity_type=null){
266 $this->send_attempts++;
267 $this->id = (int)$this->id;
268 if($delete || $this->send_attempts > 5){
270 //create new campaign log record.
272 $campaign_log = new CampaignLog();
273 $campaign_log->campaign_id=$this->campaign_id;
274 $campaign_log->target_tracker_key=$this->target_tracker_key;
275 $campaign_log->target_id= $this->related_id;
276 $campaign_log->target_type=$this->related_type;
277 $campaign_log->marketing_id=$this->marketing_id;
278 //if test suppress duplicate email address checking.
280 $campaign_log->more_information=$email_address;
282 $campaign_log->activity_type=$activity_type;
283 $campaign_log->activity_date=$timedate->now();
284 $campaign_log->list_id=$this->list_id;
285 $campaign_log->related_id= $email_id;
286 $campaign_log->related_type=$email_type;
287 $campaign_log->save();
289 $query = "DELETE FROM emailman WHERE id = $this->id";
290 $this->db->query($query);
292 //try to send the email again a day later.
293 $query = 'UPDATE ' . $this->table_name . " SET in_queue='1', send_attempts='$this->send_attempts', in_queue_date=". $this->db->now() ." WHERE id = $this->id";
294 $this->db->query($query);
299 * Function finds the reference email for the campaign. Since a campaign can have multiple email templates
300 * the reference email has same id as the marketing id.
301 * this function will create an email if one does not exist. also the function will load these relationships leads, accounts, contacts
304 * @param varchar marketing_id message id
305 * @param string $subject email subject
306 * @param string $body_text Email Body Text
307 * @param string $body_html Email Body HTML
308 * @param string $campaign_name Campaign Name
309 * @param string from_address Email address of the sender, usually email address of the configured inbox.
310 * @param string sender_id If of the user sending the campaign.
311 * @param array macro_nv array of name value pair, one row for each replacable macro in email template text.
312 * @param string from_address_name The from address eg markeing <marketing@sugar.net>
315 function create_ref_email($marketing_id,$subject,$body_text,$body_html,$campagin_name,$from_address,$sender_id,$notes,$macro_nv,$newmessage,$from_address_name) {
317 global $mod_Strings, $timedate;
318 $upd_ref_email=false;
319 if ($newmessage or empty($this->ref_email->id)) {
320 $this->ref_email = new Email();
321 $this->ref_email->retrieve($marketing_id, true, false);
323 //the reference email should be updated when user swithces from test mode to regular mode,and, for every run in test mode, and is user
324 //switches back to test mode.
325 //this is to account for changes to email template.
326 $upd_ref_email=(!empty($this->ref_email->id) and $this->ref_email->parent_type=='test' and $this->ref_email->parent_id=='test');
327 //following condition is for switching back to test mode.
328 if (!$upd_ref_email) $upd_ref_email=($this->test and !empty($this->ref_email->id) and empty($this->ref_email->parent_type) and empty($this->ref_email->parent_id));
329 if (empty($this->ref_email->id) or $upd_ref_email) {
330 //create email record.
331 $this->ref_email->id=$marketing_id;
332 $this->ref_email->date_sent = '';
334 if ($upd_ref_email==false) {
335 $this->ref_email->new_with_id=true;
338 $this->ref_email->to_addrs= '';
339 $this->ref_email->to_addrs_ids = '';
340 $this->ref_email->to_addrs_names = '';
341 $this->ref_email->to_addrs_emails ='';
342 $this->ref_email->type= 'campaign';
343 $this->ref_email->deleted = '0';
344 $this->ref_email->name = $campagin_name.': '.$subject ;
345 $this->ref_email->description_html = $body_html;
346 $this->ref_email->description = $body_text;
347 $this->ref_email->from_addr = $from_address;
348 $this->ref_email->from_addr_name = $from_address_name;
349 $this->ref_email->assigned_user_id = $sender_id;
351 $this->ref_email->parent_type = 'test';
352 $this->ref_email->parent_id = 'test';
354 $this->ref_email->parent_type = '';
355 $this->ref_email->parent_id = '';
357 $this->ref_email->date_start = $timedate->nowDate();
358 $this->ref_email->time_start = $timedate->asUserTime($timedate->getNow(true));
360 $this->ref_email->status='sent';
361 $retId = $this->ref_email->save();
363 foreach($notes as $note) {
364 if($note->object_name == 'Note') {
365 if (! empty($note->file->temp_file_location) && is_file($note->file->temp_file_location)) {
366 $file_location = $note->file->temp_file_location;
367 $filename = $note->file->original_file_name;
368 $mime_type = $note->file->mime_type;
370 $file_location = "upload://{$note->id}";
371 $filename = $note->id.$note->filename;
372 $mime_type = $note->file_mime_type;
374 } elseif($note->object_name == 'DocumentRevision') { // from Documents
375 $filename = $note->id.$note->filename;
376 $file_location = "upload://$filename";
377 $mime_type = $note->file_mime_type;
380 $noteAudit = new Note();
381 $noteAudit->parent_id = $retId;
382 $noteAudit->parent_type = $this->ref_email->module_dir;
383 $noteAudit->description = "[".$note->filename."] ".$mod_strings['LBL_ATTACHMENT_AUDIT'];
384 $noteAudit->filename=$filename;
385 $noteAudit->file_mime_type=$mime_type;
386 $noteAudit_id=$noteAudit->save();
388 UploadFile::duplicate_file($note->id, $noteAudit_id, $filename);
392 //load relationships.
393 $this->ref_email->load_relationship('users');
394 $this->ref_email->load_relationship('prospects');
395 $this->ref_email->load_relationship('contacts');
396 $this->ref_email->load_relationship('leads');
397 $this->ref_email->load_relationship('accounts');
400 if (!empty($this->related_id ) && !empty($this->related_type)) {
402 //save relationships.
403 switch ($this->related_type) {
409 $rel_name="prospects";
413 $rel_name="contacts";
421 $rel_name="accounts";
425 //serialize data to be passed into Link2->add() function
426 $campaignData = serialize($macro_nv);
428 //required for one email per campaign per marketing message.
429 $this->ref_email->$rel_name->add($this->related_id,array('campaign_data'=>$this->db->quote($campaignData)));
431 return $this->ref_email->id;
435 * The function creates a copy of email send to each target.
437 function create_indiv_email($module,$mail) {
439 global $locale, $timedate;
440 $email = new Email();
441 $email->to_addrs= $module->name . '<'.$module->email1.'>';
442 $email->to_addrs_ids = $module->id .';';
443 $email->to_addrs_names = $module->name . ';';
444 $email->to_addrs_emails = $module->email1 . ';';
445 $email->type= 'archived';
446 $email->deleted = '0';
447 $email->name = $this->current_campaign->name.': '.$mail->Subject ;
448 if ($mail->ContentType == "text/plain") {
449 $email->description = $mail->Body;
450 $email->description_html =null;
452 $email->description_html = $mail->Body;
453 $email->description = $mail->AltBody;
455 $email->from_addr = $mail->From;
456 $email->assigned_user_id = $this->user_id;
457 $email->parent_type = $this->related_type;
458 $email->parent_id = $this->related_id ;
460 $email->date_start = $timedate->nowDbDate();
461 $email->time_start = $timedate->asDbTime($timedate->getNow());
462 $email->status='sent';
463 $retId = $email->save();
465 foreach($this->notes_array as $note) {
466 if(!class_exists('Note')) {
469 // create "audit" email without duping off the file to save on disk space
470 $noteAudit = new Note();
471 $noteAudit->parent_id = $retId;
472 $noteAudit->parent_type = $email->module_dir;
473 $noteAudit->description = "[".$note->filename."] ".$mod_strings['LBL_ATTACHMENT_AUDIT'];
477 if (!empty($this->related_id ) && !empty($this->related_type)) {
479 //save relationships.
480 switch ($this->related_type) {
486 $rel_name="prospects";
490 $rel_name="contacts";
498 $rel_name="accounts";
502 if (!empty($rel_name)) {
503 $email->load_relationship($rel_name);
504 $email->$rel_name->add($this->related_id);
510 * Call this function to verify the email_marketing message and email_template configured
511 * for the campaign. If issues are found a fatal error will be logged but processing will not stop.
512 * @return Boolean Returns true if all campaign parameters are set correctly
514 function verify_campaign($marketing_id) {
516 if (!isset($this->verified_email_marketing_ids[$marketing_id])) {
517 if (!class_exists('EmailMarketing')) {
520 $email_marketing = new EmailMarketing();
521 $ret=$email_marketing->retrieve($marketing_id);
523 $GLOBALS['log']->fatal('Error retrieving marketing message for the email campaign. marketing_id = ' .$marketing_id);
527 //verify the email template.
528 if (empty($email_marketing->template_id)) {
529 $GLOBALS['log']->fatal('Error retrieving template for the email campaign. marketing_id = ' .$marketing_id);
533 if (!class_exists('EmailTemplate')) {
536 $emailtemplate= new EmailTemplate();
538 $ret=$emailtemplate->retrieve($email_marketing->template_id);
540 $GLOBALS['log']->fatal('Error retrieving template for the email campaign. template_id = ' .$email_marketing->template_id);
544 if (empty($emailtemplate->subject) and empty($emailtemplate->body) and empty($emailtemplate->body_html)) {
545 $GLOBALS['log']->fatal('Email template is empty. email_template_id=' .$email_marketing->template_id);
550 $this->verified_email_marketing_ids[$marketing_id]=1;
554 function sendEmail($mail,$save_emails=1,$testmode=false){
555 $this->test=$testmode;
557 global $beanList, $beanFiles, $sugar_config;
560 $OBCharset = $locale->getPrecedentPreference('default_email_charset');
561 $mod_strings = return_module_language( $sugar_config['default_language'], 'EmailMan');
563 //get tracking entities locations.
564 if (!isset($this->tracking_url)) {
565 if (!class_exists('Administration')) {
568 $admin=new Administration();
569 $admin->retrieveSettings('massemailer'); //retrieve all admin settings.
570 if (isset($admin->settings['massemailer_tracking_entities_location_type']) and $admin->settings['massemailer_tracking_entities_location_type']=='2' and isset($admin->settings['massemailer_tracking_entities_location']) ) {
571 $this->tracking_url=$admin->settings['massemailer_tracking_entities_location'];
573 $this->tracking_url=$sugar_config['site_url'];
577 //make sure tracking url ends with '/' character
578 $strLen = strlen($this->tracking_url);
579 if($this->tracking_url{$strLen-1} !='/'){
580 $this->tracking_url .='/';
583 if(!isset($beanList[$this->related_type])){
586 $class = $beanList[$this->related_type];
587 if (!class_exists($class)) {
588 require_once($beanFiles[$class]);
591 if (!class_exists('Email')) {
595 //prepare variables for 'set_as_sent' function
596 $this->target_tracker_key = create_guid();
598 $module = new $class();
599 $module->retrieve($this->related_id);
600 $module->emailAddress->handleLegacyRetrieve($module);
602 //check to see if bean has a primary email address
603 if (!$this->is_primary_email_address($module)) {
604 //no primary email address designated, do not send out email, create campaign log
605 //of type send error to denote that this user was not emailed
606 $this->set_as_sent($module->email1, true,null,null,'send error');
607 //create fatal logging for easy review of cause.
608 $GLOBALS['log']->fatal('Email Address provided is not Primary Address for email with id ' . $module->email1 . "' Emailman id=$this->id");
612 if (!$this->valid_email_address($module->email1)) {
613 $this->set_as_sent($module->email1, true,null,null,'invalid email');
614 $GLOBALS['log']->fatal('Encountered invalid email address' . $module->email1 . " Emailman id=$this->id");
618 if ((!isset($module->email_opt_out)
619 || ($module->email_opt_out !== 'on'
620 && $module->email_opt_out !== 1
621 && $module->email_opt_out !== '1'))
622 && (!isset($module->invalid_email)
623 || ($module->invalid_email !== 'on'
624 && $module->invalid_email !== 1
625 && $module->invalid_email !== '1'))){
626 $lower_email_address=strtolower($module->email1);
627 //test against indivdual address.
628 if (isset($this->restricted_addresses) and isset($this->restricted_addresses[$lower_email_address])) {
629 $this->set_as_sent($lower_email_address, true,null,null,'blocked');
632 //test against restricted domains
633 $at_pos=strrpos($lower_email_address,'@');
634 if ($at_pos !== false) {
635 foreach ($this->restricted_domains as $domain=>$value) {
636 $pos=strrpos($lower_email_address,$domain);
637 if ($pos !== false && $pos > $at_pos) {
639 $this->set_as_sent($lower_email_address, true,null,null,'blocked');
645 //test for duplicate email address by marketing id.
646 $dup_query="select id from campaign_log where more_information='".$this->db->quote($module->email1)."' and marketing_id='".$this->marketing_id."'";
647 $dup=$this->db->query($dup_query);
648 $dup_row=$this->db->fetchByAssoc($dup);
649 if (!empty($dup_row)) {
650 //we have seen this email address before
651 $this->set_as_sent($module->email1,true,null,null,'blocked');
656 //fetch email marketing.
657 if (empty($this->current_emailmarketing) or !isset($this->current_emailmarketing)) {
658 if (!class_exists('EmailMarketing')) {
662 $this->current_emailmarketing=new EmailMarketing();
665 if (empty($this->current_emailmarketing->id) or $this->current_emailmarketing->id !== $this->marketing_id) {
666 $this->current_emailmarketing->retrieve($this->marketing_id);
668 $this->newmessage = true;
670 //fetch email template associate with the marketing message.
671 if (empty($this->current_emailtemplate) or $this->current_emailtemplate->id !== $this->current_emailmarketing->template_id) {
672 if (!class_exists('EmailTemplate')) {
675 $this->current_emailtemplate= new EmailTemplate();
677 $this->current_emailtemplate->retrieve($this->current_emailmarketing->template_id);
679 //escape email template contents.
680 $this->current_emailtemplate->subject=from_html($this->current_emailtemplate->subject);
681 $this->current_emailtemplate->body_html=from_html($this->current_emailtemplate->body_html);
682 $this->current_emailtemplate->body=from_html($this->current_emailtemplate->body);
684 $q = "SELECT * FROM notes WHERE parent_id = '".$this->current_emailtemplate->id."' AND deleted = 0";
685 $r = $this->db->query($q);
687 // cn: bug 4684 - initialize the notes array, else old data is still around for the next round
688 $this->notes_array = array();
689 if (!class_exists('Note')){
690 require_once('modules/Notes/Note.php');
692 while($a = $this->db->fetchByAssoc($r)) {
693 $noteTemplate = new Note();
694 $noteTemplate->retrieve($a['id']);
695 $this->notes_array[] = $noteTemplate;
699 // fetch mailbox details..
700 if(empty($this->current_mailbox)) {
701 if (!class_exists('InboundEmail')) {
704 $this->current_mailbox= new InboundEmail();
706 if (empty($this->current_mailbox->id) or $this->current_mailbox->id !== $this->current_emailmarketing->inbound_email_id) {
707 $this->current_mailbox->retrieve($this->current_emailmarketing->inbound_email_id);
708 //extract the email address.
709 $this->mailbox_from_addr=$this->current_mailbox->get_stored_options('from_addr','nobody@example.com',null);
712 // fetch campaign details..
713 if (empty($this->current_campaign)) {
714 if (!class_exists('Campaign')) {
717 $this->current_campaign= new Campaign();
719 if (empty($this->current_campaign->id) or $this->current_campaign->id !== $this->current_emailmarketing->campaign_id) {
720 $this->current_campaign->retrieve($this->current_emailmarketing->campaign_id);
722 //load defined tracked_urls
723 $this->current_campaign->load_relationship('tracked_urls');
724 $query_array=$this->current_campaign->tracked_urls->getQuery(true);
725 $query_array['select']="SELECT tracker_name, tracker_key, id, is_optout ";
726 $result=$this->current_campaign->db->query(implode(' ',$query_array));
728 $this->has_optout_links=false;
729 $this->tracker_urls=array();
730 while (($row=$this->current_campaign->db->fetchByAssoc($result)) != null) {
731 $this->tracker_urls['{'.$row['tracker_name'].'}']=$row;
732 //has the user defined opt-out links for the campaign.
733 if ($row['is_optout']==1) {
734 $this->has_optout_links=true;
739 $mail->ClearAllRecipients();
740 $mail->ClearReplyTos();
741 $mail->Sender = $this->mailbox_from_addr;
742 $mail->From = $this->mailbox_from_addr;
743 $mail->FromName = $locale->translateCharsetMIME(trim($this->current_emailmarketing->from_name), 'UTF-8', $OBCharset);
744 $mail->ClearCustomHeaders();
745 $mail->AddCustomHeader('X-CampTrackID:'.$this->target_tracker_key);
746 //CL - Bug 25256 Check if we have a reply_to_name/reply_to_addr value from the email marketing table. If so use email marketing entry; otherwise current mailbox (inbound email) entry
747 $replyToName = empty($this->current_emailmarketing->reply_to_name) ? $this->current_mailbox->get_stored_options('reply_to_name',$mail->FromName,null) : $this->current_emailmarketing->reply_to_name;
748 $replyToAddr = empty($this->current_emailmarketing->reply_to_addr) ? $this->current_mailbox->get_stored_options('reply_to_addr',$mail->From,null) : $this->current_emailmarketing->reply_to_addr;
750 if (!empty($replyToAddr)) {
751 $mail->AddReplyTo($replyToAddr,$locale->translateCharsetMIME(trim($replyToName), 'UTF-8', $OBCharset));
754 //parse and replace bean variables.
756 $focus_name = 'Contacts';
757 if($module->module_dir == 'Accounts')
759 $focus_name = 'Accounts';
763 $template_data= $this->current_emailtemplate->parse_email_template(array('subject'=>$this->current_emailtemplate->subject,
764 'body_html'=>$this->current_emailtemplate->body_html,
765 'body'=>$this->current_emailtemplate->body,
767 ,$focus_name, $module
770 //add email address to this list.
771 $macro_nv['sugar_to_email_address']=$module->email1;
772 $macro_nv['email_template_id']=$this->current_emailmarketing->template_id;
774 //parse and replace urls.
775 //this is new style of adding tracked urls to a campaign.
776 $tracker_url_template= $this->tracking_url . 'index.php?entryPoint=campaign_trackerv2&track=%s'.'&identifier='.$this->target_tracker_key;
777 $removeme_url_template=$this->tracking_url . 'index.php?entryPoint=removeme&identifier='.$this->target_tracker_key;
778 $template_data= $this->current_emailtemplate->parse_tracker_urls($template_data,$tracker_url_template,$this->tracker_urls,$removeme_url_template);
779 $mail->AddAddress($module->email1,$locale->translateCharsetMIME(trim($module->name), 'UTF-8', $OBCharset) );
781 //refetch strings in case they have been changed by creation of email templates or other beans.
782 $mod_strings = return_module_language( $sugar_config['default_language'], 'EmailMan');
785 $mail->Subject = $mod_strings['LBL_PREPEND_TEST'] . $template_data['subject'];
787 $mail->Subject = $template_data['subject'];
790 //check if this template is meant to be used as "text only"
792 if(isset($this->current_emailtemplate->text_only) && $this->current_emailtemplate->text_only){$text_only =true;}
793 //if this template is textonly, then just send text body. Do not add tracker, opt out,
794 //or perform other processing as it will not show up in text only email
796 $this->description_html = '';
797 $mail->IsHTML(false);
798 $mail->Body = $template_data['body'];
801 $mail->Body = wordwrap($template_data['body_html'], 900);
802 //BEGIN:this code will trigger for only campaigns pending before upgrade to 4.2.0.
803 //will be removed for the next release.
804 if(!isset($btracker)) $btracker=false;
806 $mail->Body .= "<br /><br /><a href='". $tracker_url ."'>" . $tracker_text . "</a><br /><br />";
808 if (!empty($tracker_url)) {
809 $mail->Body = str_replace('TRACKER_URL_START', "<a href='" . $tracker_url ."'>", $mail->Body);
810 $mail->Body = str_replace('TRACKER_URL_END', "</a>", $mail->Body);
811 $mail->AltBody = str_replace('TRACKER_URL_START', "<a href='" . $tracker_url ."'>", $mail->AltBody);
812 $mail->AltBody = str_replace('TRACKER_URL_END', "</a>", $mail->AltBody);
817 //do not add the default remove me link if the campaign has a trackerurl of the opotout link
818 if ($this->has_optout_links==false) {
819 $mail->Body .= "<br /><span style='font-size:0.8em'>{$mod_strings['TXT_REMOVE_ME']} <a href='". $this->tracking_url . "index.php?entryPoint=removeme&identifier={$this->target_tracker_key}'>{$mod_strings['TXT_REMOVE_ME_CLICK']}</a></span>";
821 // cn: bug 11979 - adding single quote to comform with HTML email RFC
822 $mail->Body .= "<br /><img alt='' height='1' width='1' src='{$this->tracking_url}index.php?entryPoint=image&identifier={$this->target_tracker_key}' />";
824 $mail->AltBody = $template_data['body'];
826 $mail->AltBody .="\n". $tracker_url;
828 if ($this->has_optout_links==false) {
829 $mail->AltBody .="\n\n\n{$mod_strings['TXT_REMOVE_ME_ALT']} ". $this->tracking_url . "index.php?entryPoint=removeme&identifier=$this->target_tracker_key";
834 // cn: bug 4684, handle attachments in email templates.
835 $mail->handleAttachments($this->notes_array);
836 $tmp_Subject = $mail->Subject;
837 $mail->prepForOutbound();
839 $success = $mail->Send();
840 //Do not save the encoded subject.
841 $mail->Subject = $tmp_Subject;
844 if ($save_emails==1) {
845 $email_id=$this->create_indiv_email($module,$mail);
847 //find/create reference email record. all campaign targets reveiving this message will be linked with this message.
848 $decodedFromName = mb_decode_mimeheader($this->current_emailmarketing->from_name);
849 $fromAddressName= "{$decodedFromName} <{$this->mailbox_from_addr}>";
851 $email_id=$this->create_ref_email($this->marketing_id,
852 $this->current_emailtemplate->subject,
853 $this->current_emailtemplate->body,
854 $this->current_emailtemplate->body_html,
855 $this->current_campaign->name,
856 $this->mailbox_from_addr,
863 $this->newmessage = false;
868 $this->set_as_sent($module->email1, true, $email_id, 'Emails', 'targeted');
871 if(!empty($layout_def['parent_id'])) {
872 if (isset($layout_def['fields'][strtoupper($layout_def['parent_id'])])) {
873 $parent.="&parent_id=".$layout_def['fields'][strtoupper($layout_def['parent_id'])];
876 if(!empty($layout_def['parent_module'])) {
877 if (isset($layout_def['fields'][strtoupper($layout_def['parent_module'])])) {
878 $parent.="&parent_module=".$layout_def['fields'][strtoupper($layout_def['parent_module'])];
881 //log send error. save for next attempt after 24hrs. no campaign log entry will be created.
882 $this->set_as_sent($module->email1,false,null,null,'send error');
886 $this->target_tracker_key=create_guid();
888 if (isset($module->email_opt_out) && ($module->email_opt_out === 'on' || $module->email_opt_out == '1' || $module->email_opt_out == 1)) {
889 $this->set_as_sent($module->email1,true,null,null,'removed');
891 if (isset($module->invalid_email) && ($module->invalid_email == 1 || $module->invalid_email == '1')) {
892 $this->set_as_sent($module->email1,true,null,null,'invalid email');
894 $this->set_as_sent($module->email1,true, null,null,'send error');
903 * Validates the passed email address.
904 * Limitations of this algorithm: does not validate email addressess that end with .meuseum
907 function valid_email_address($email_address) {
909 $email_address=trim($email_address);
910 if (empty($email_address)) {
914 $pattern='/[A-Z0-9\._%-]+@[A-Z0-9\.-]+\.[A-Za-z]{2,}$/i';
915 $ret=preg_match($pattern, $email_address);
917 if ($ret===false or $ret==0) {
924 * This function takes in the given bean and searches for a related email address
925 * that has been designated as primary. If one is found, true is returned
926 * If no primary email address is found, then false is returned
929 function is_primary_email_address($bean){
930 $email_address=trim($bean->email1);
932 if (empty($email_address)) {
935 //query for this email address rel and see if this is primary address
936 $primary_qry = "select email_address_id from email_addr_bean_rel where bean_id = '".$bean->id."' and email_addr_bean_rel.primary_address=1 and deleted=0";
937 $res = $bean->db->query($primary_qry);
938 $prim_row=$this->db->fetchByAssoc($res);
939 //return true if this is primary
940 if (!empty($prim_row)) {
947 function create_export_query(&$order_by, &$where)
949 $custom_join = $this->getCustomJoin(true, true, $where);
950 $query = "SELECT emailman.*";
951 $query .= $custom_join['select'];
953 $query .= " FROM emailman ";
955 $query .= $custom_join['join'];
957 $where_auto = "( emailman.deleted IS NULL OR emailman.deleted=0 )";
960 $query .= "where ($where) AND ".$where_auto;
962 $query .= "where ".$where_auto;
964 if(!empty($order_by))
966 $query .= ' ORDER BY '. $this->process_order_by($order_by, null);
973 * Actuall deletes the emailman record
976 public function mark_deleted($id)
978 $this->db->query("DELETE FROM {$this->table_name} WHERE id=".intval($id));