]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - modules/EmailMan/EmailMan.php
Release 6.5.15
[Github/sugarcrm.git] / modules / EmailMan / EmailMan.php
1 <?php
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.
6  * 
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.
13  * 
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
17  * details.
18  * 
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
22  * 02110-1301 USA.
23  * 
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.
26  * 
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.
30  * 
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  ********************************************************************************/
37
38
39
40 class EmailMan extends SugarBean{
41         var $id;
42         var $deleted;
43         var $date_created;
44         var $date_modified;
45         var $module;
46         var $module_id;
47         var $marketing_id;
48         var $campaign_id;
49         var $user_id;
50         var $list_id;
51         var $invalid_email;
52         var $from_name;
53         var $from_email;
54         var $in_queue;
55         var $in_queue_date;
56         var $template_id;
57         var $send_date_time;
58         var $table_name = "emailman";
59         var $object_name = "EmailMan";
60         var $module_dir = "EmailMan";
61         var $send_attempts;
62         var $related_id;
63         var $related_type;
64         var $test=false;
65         var $notes_array = array();
66     var $verified_email_marketing_ids =  array();
67         function toString(){
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";
69         }
70
71     // This is used to retrieve related fields from form posts.
72         var $additional_column_fields = array();
73
74         function EmailMan() {
75                 parent::SugarBean();
76
77         }
78
79         var $new_schema = true;
80
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' => '');
83
84
85
86                 $query['select'] = "SELECT $this->table_name.* ,
87                                         campaigns.name as campaign_name,
88                                         email_marketing.name as message_name,
89                                         (CASE related_type
90                                                 WHEN 'Contacts' THEN ".$this->db->concat('contacts', array('first_name', 'last_name'), '&nbsp;')."
91                                                 WHEN 'Leads' THEN ".$this->db->concat('leads', array('first_name', 'last_name'), '&nbsp;')."
92                                                 WHEN 'Accounts' THEN accounts.name
93                                                 WHEN 'Users' THEN ".$this->db->concat('users', array('first_name', 'last_name'), '&nbsp;')."
94                                                 WHEN 'Prospects' THEN ".$this->db->concat('prospects', array('first_name', 'last_name'), '&nbsp;')."
95                                         END) recipient_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 ";
106
107                 $where_auto = " $this->table_name.deleted=0";
108
109         if($where != "")
110                         $query['where'] = "WHERE $where AND ".$where_auto;
111                 else
112                         $query['where'] = "WHERE ".$where_auto;
113
114         if(isset($params['group_by'])) {
115             $query['group_by'] .= " GROUP BY {$params['group_by']}";
116                 }
117
118         $order_by = $this->process_order_by($order_by);
119         if (!empty($order_by)) {
120             $query['order_by'] = ' ORDER BY ' . $order_by;
121         }
122
123                 if ($return_array) {
124                         return $query;
125                 }
126
127                 return  $query['select'] . $query['from'] . $query['where']. $query['order_by'];
128
129     } // if
130
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) {
132
133                 if ($return_array) {
134                         return parent::create_new_list_query($order_by, $where,$filter,$params, $show_deleted,$join_type, $return_array,$parentbean, $singleSelect);
135                 }
136
137                 $query = "SELECT $this->table_name.* ,
138                                         campaigns.name as campaign_name,
139                                         email_marketing.name as message_name,
140                                         (CASE related_type
141                                                 WHEN 'Contacts' THEN ".$this->db->concat('contacts', array('first_name', 'last_name'), '&nbsp;')."
142                                                 WHEN 'Leads' THEN ".$this->db->concat('leads', array('first_name', 'last_name'), '&nbsp;')."
143                                                 WHEN 'Accounts' THEN accounts.name
144                                                 WHEN 'Users' THEN ".$this->db->concat('users', array('first_name', 'last_name'), '&nbsp;')."
145                                                 WHEN 'Prospects' THEN ".$this->db->concat('prospects', array('first_name', 'last_name'), '&nbsp;')."
146                                         END) recipient_name";
147
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 ";
158
159                  //B.F. #37943
160                 if( isset($params['group_by']) )
161                 {
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     ";
165                 }
166
167                 $where_auto = " $this->table_name.deleted=0";
168
169         if($where != "")
170                         $query .= "WHERE $where AND ".$where_auto;
171                 else
172                         $query .= "WHERE ".$where_auto;
173
174         $order_by = $this->process_order_by($order_by);
175         if (!empty($order_by)) {
176             $query .= ' ORDER BY ' . $order_by;
177         }
178
179                 return $query;
180
181     }
182
183         function create_list_query($order_by, $where, $show_deleted = 0){
184
185                 $query = "SELECT $this->table_name.* ,
186                                         campaigns.name as campaign_name,
187                                         email_marketing.name as message_name,
188                                         (CASE related_type
189                                                 WHEN 'Contacts' THEN ".$this->db->concat('contacts', array('first_name', 'last_name'), '&nbsp;')."
190                                                 WHEN 'Leads' THEN ".$this->db->concat('leads', array('first_name', 'last_name'), '&nbsp;')."
191                                                 WHEN 'Accounts' THEN accounts.name
192                                                 WHEN 'Users' THEN ".$this->db->concat('users', array('first_name', 'last_name'), '&nbsp;')."
193                                                 WHEN 'Prospects' THEN ".$this->db->concat('prospects', array('first_name', 'last_name'), '&nbsp;')."
194                                         END) recipient_name";
195                 $query .= "     FROM $this->table_name
196                                         LEFT JOIN users ON users.id = $this->table_name.related_id and $this->table_name.related_type ='Users'
197                                         LEFT JOIN contacts ON contacts.id = $this->table_name.related_id and $this->table_name.related_type ='Contacts'
198                                         LEFT JOIN leads ON leads.id = $this->table_name.related_id and $this->table_name.related_type ='Leads'
199                                         LEFT JOIN accounts ON accounts.id = $this->table_name.related_id and $this->table_name.related_type ='Accounts'
200                                         LEFT JOIN prospects ON prospects.id = $this->table_name.related_id and $this->table_name.related_type ='Prospects'
201                                         LEFT JOIN prospect_lists ON prospect_lists.id = $this->table_name.list_id
202                     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
203                                         LEFT JOIN campaigns ON campaigns.id = $this->table_name.campaign_id
204                                         LEFT JOIN email_marketing ON email_marketing.id = $this->table_name.marketing_id ";
205
206                 $where_auto = " $this->table_name.deleted=0";
207
208         if($where != "")
209                         $query .= "where $where AND ".$where_auto;
210                 else
211                         $query .= "where ".$where_auto;
212
213         $order_by = $this->process_order_by($order_by);
214         if (!empty($order_by)) {
215             $query .= ' ORDER BY ' . $order_by;
216         }
217
218                 return $query;
219         }
220
221     function get_list_view_data()
222     {
223         global $locale, $current_user;
224         $temp_array = parent::get_list_view_array();
225
226         $related_type = $temp_array['RELATED_TYPE'];
227         $related_id = $temp_array['RELATED_ID'];
228         $is_person = SugarModule::get($related_type)->moduleImplements('Person');
229
230         if($is_person)
231         {
232             $query = "SELECT first_name, last_name FROM ". strtolower($related_type) ." WHERE id ='". $related_id ."'";
233         } else {
234             $query = "SELECT name FROM ". strtolower($related_type) ." WHERE id ='". $related_id ."'";
235         }
236
237         $result=$this->db->query($query);
238         $row=$this->db->fetchByAssoc($result);
239
240         if($row)
241         {
242                 $temp_array['RECIPIENT_NAME'] = $is_person ? $locale->getLocaleFormattedName($row['first_name'], $row['last_name'], '') : $row['name'];
243         }
244
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'";
247
248         $result=$this->db->query($query);
249         $row=$this->db->fetchByAssoc($result);
250         if ($row)
251         {
252             $temp_array['RECIPIENT_EMAIL']=$row['email_address'];
253         }
254
255         $this->email1 = $temp_array['RECIPIENT_EMAIL'];
256                 $temp_array['EMAIL1_LINK'] = $current_user->getEmailLink('email1', $this, '', '', 'ListView');
257
258         return $temp_array;
259     }
260
261
262         function set_as_sent($email_address, $delete= true,$email_id=null, $email_type=null,$activity_type=null){
263
264                 global $timedate;
265
266                 $this->send_attempts++;
267                 $this->id = (int)$this->id;
268                 if($delete || $this->send_attempts > 5){
269
270                         //create new campaign log record.
271
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.
279                         if (!$this->test) {
280                                 $campaign_log->more_information=$email_address;
281                         }
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();
288
289                         $query = "DELETE FROM emailman WHERE id = $this->id";
290                         $this->db->query($query);
291                 }else{
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);
295                 }
296         }
297
298     /**
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
302      * users and targets
303      *
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>
313      * @return
314      */
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) {
316
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);
322
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 = '';
333
334                 if ($upd_ref_email==false) {
335                     $this->ref_email->new_with_id=true;
336                 }
337
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;
350                 if ($this->test) {
351                     $this->ref_email->parent_type = 'test';
352                     $this->ref_email->parent_id =  'test';
353                 } else {
354                     $this->ref_email->parent_type = '';
355                     $this->ref_email->parent_id =  '';
356                 }
357                 $this->ref_email->date_start = $timedate->nowDate();
358                 $this->ref_email->time_start = $timedate->asUserTime($timedate->getNow(true));
359
360                 $this->ref_email->status='sent';
361                 $retId = $this->ref_email->save();
362
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;
369                         } else {
370                             $file_location = "upload://{$note->id}";
371                             $filename = $note->id.$note->filename;
372                             $mime_type = $note->file_mime_type;
373                         }
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;
378                     }
379
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();
387
388                     UploadFile::duplicate_file($note->id, $noteAudit_id, $filename);
389                 }
390             }
391
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');
398        }
399
400        if (!empty($this->related_id ) && !empty($this->related_type)) {
401
402             //save relationships.
403             switch ($this->related_type)  {
404                 case 'Users':
405                     $rel_name="users";
406                     break;
407
408                 case 'Prospects':
409                     $rel_name="prospects";
410                     break;
411
412                 case 'Contacts':
413                     $rel_name="contacts";
414                     break;
415
416                 case 'Leads':
417                     $rel_name="leads";
418                     break;
419
420                 case 'Accounts':
421                     $rel_name="accounts";
422                     break;
423             }
424
425             //serialize data to be passed into Link2->add() function
426             $campaignData = serialize($macro_nv);
427
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)));
430        }
431        return $this->ref_email->id;
432     }
433
434    /**
435     * The function creates a copy of email send to each target.
436     */
437     function create_indiv_email($module,$mail) {
438
439         global $locale, $timedate;
440         $email = new Email();
441         $email->to_addrs= $module->name . '&lt;'.$module->email1.'&gt;';
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;
451         } else {
452             $email->description_html = $mail->Body;
453             $email->description = $mail->AltBody;
454         }
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 ;
459
460         $email->date_start = $timedate->nowDbDate();
461         $email->time_start = $timedate->asDbTime($timedate->getNow());
462         $email->status='sent';
463         $retId = $email->save();
464
465         foreach($this->notes_array as $note) {
466             if(!class_exists('Note')) {
467
468             }
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'];
474             $noteAudit->save();
475         }
476
477         if (!empty($this->related_id ) && !empty($this->related_type)) {
478
479                 //save relationships.
480                 switch ($this->related_type)  {
481                     case 'Users':
482                         $rel_name="users";
483                         break;
484
485                     case 'Prospects':
486                         $rel_name="prospects";
487                         break;
488
489                     case 'Contacts':
490                         $rel_name="contacts";
491                         break;
492
493                     case 'Leads':
494                         $rel_name="leads";
495                         break;
496
497                     case 'Accounts':
498                         $rel_name="accounts";
499                         break;
500                 }
501
502                 if (!empty($rel_name)) {
503                     $email->load_relationship($rel_name);
504                     $email->$rel_name->add($this->related_id);
505                 }
506         }
507         return $email->id;
508     }
509     /*
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
513      */
514     function verify_campaign($marketing_id) {
515
516         if (!isset($this->verified_email_marketing_ids[$marketing_id])) {
517             if (!class_exists('EmailMarketing')) {
518
519             }
520             $email_marketing = new EmailMarketing();
521             $ret=$email_marketing->retrieve($marketing_id);
522             if (empty($ret)) {
523                 $GLOBALS['log']->fatal('Error retrieving marketing message for the email campaign. marketing_id = ' .$marketing_id);
524                 return false;
525             }
526
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);
530                 return false;
531             }
532
533             if (!class_exists('EmailTemplate')) {
534
535             }
536             $emailtemplate= new EmailTemplate();
537
538             $ret=$emailtemplate->retrieve($email_marketing->template_id);
539             if (empty($ret)) {
540                 $GLOBALS['log']->fatal('Error retrieving template for the email campaign. template_id = ' .$email_marketing->template_id);
541                 return false;
542             }
543
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);
546                                 return false;
547             }
548
549         }
550         $this->verified_email_marketing_ids[$marketing_id]=1;
551
552         return true;
553     }
554         function sendEmail($mail,$save_emails=1,$testmode=false){
555             $this->test=$testmode;
556
557                 global $beanList, $beanFiles, $sugar_config;
558                 global $mod_strings;
559         global $locale;
560         $OBCharset = $locale->getPrecedentPreference('default_email_charset');
561                 $mod_strings = return_module_language( $sugar_config['default_language'], 'EmailMan');
562
563                 //get tracking entities locations.
564                 if (!isset($this->tracking_url)) {
565                         if (!class_exists('Administration')) {
566
567                         }
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'];
572                     } else {
573                                 $this->tracking_url=$sugar_config['site_url'];
574                     }
575                 }
576
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 .='/';
581         }
582
583                 if(!isset($beanList[$this->related_type])){
584                         return false;
585                 }
586                 $class = $beanList[$this->related_type];
587                 if (!class_exists($class)) {
588                         require_once($beanFiles[$class]);
589                 }
590
591                 if (!class_exists('Email')) {
592
593                 }
594
595         //prepare variables for 'set_as_sent' function
596         $this->target_tracker_key = create_guid();
597
598         $module = new $class();
599                 $module->retrieve($this->related_id);
600                 $module->emailAddress->handleLegacyRetrieve($module);
601
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");
609             return true;
610         }
611
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");
615                         return true;
616                 }
617
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');
630                                 return true;
631                         }
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) {
638                                                 //found
639                                                 $this->set_as_sent($lower_email_address, true,null,null,'blocked');
640                                                 return true;
641                                         }
642                                 }
643                         }
644
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');
652                                 return true;
653                         }
654
655
656                         //fetch email marketing.
657                         if (empty($this->current_emailmarketing) or !isset($this->current_emailmarketing)) {
658                                 if (!class_exists('EmailMarketing')) {
659
660                                 }
661
662                                 $this->current_emailmarketing=new EmailMarketing();
663
664                         }
665                         if (empty($this->current_emailmarketing->id) or $this->current_emailmarketing->id !== $this->marketing_id) {
666                                 $this->current_emailmarketing->retrieve($this->marketing_id);
667
668                 $this->newmessage = true;
669                         }
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')) {
673
674                                 }
675                                 $this->current_emailtemplate= new EmailTemplate();
676
677                                 $this->current_emailtemplate->retrieve($this->current_emailmarketing->template_id);
678
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);
683
684                                 $q = "SELECT * FROM notes WHERE parent_id = '".$this->current_emailtemplate->id."' AND deleted = 0";
685                                 $r = $this->db->query($q);
686
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');
691                                 }
692                                 while($a = $this->db->fetchByAssoc($r)) {
693                                         $noteTemplate = new Note();
694                                         $noteTemplate->retrieve($a['id']);
695                                         $this->notes_array[] = $noteTemplate;
696                                 }
697                         }
698
699                         // fetch mailbox details..
700                         if(empty($this->current_mailbox)) {
701                                 if (!class_exists('InboundEmail')) {
702
703                                 }
704                                 $this->current_mailbox= new InboundEmail();
705                         }
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);
710                         }
711
712                         // fetch campaign details..
713                         if (empty($this->current_campaign)) {
714                                 if (!class_exists('Campaign')) {
715
716                                 }
717                                 $this->current_campaign= new Campaign();
718                         }
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);
721
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));
727
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;
735                                         }
736                                 }
737                         }
738
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;
749
750             if (!empty($replyToAddr)) {
751                 $mail->AddReplyTo($replyToAddr,$locale->translateCharsetMIME(trim($replyToName), 'UTF-8', $OBCharset));
752             }
753
754                         //parse and replace bean variables.
755             $macro_nv=array();
756             $focus_name = 'Contacts';
757             if($module->module_dir == 'Accounts')
758             {
759                 $focus_name = 'Accounts';
760             }
761
762
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,
766                                                                                                                                                                           )
767                                                                                                                                                                           ,$focus_name, $module
768                                                                                       ,$macro_nv);
769
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;
773
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) );
780
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');
783
784             if($this->test){
785                 $mail->Subject =  $mod_strings['LBL_PREPEND_TEST'] . $template_data['subject'];
786             }else{
787                 $mail->Subject =  $template_data['subject'];
788             }
789
790             //check if this template is meant to be used as "text only"
791             $text_only = false;
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
795             if($text_only){
796                 $this->description_html = '';
797                 $mail->IsHTML(false);
798                 $mail->Body = $template_data['body'];
799
800             }else{
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;
805                 if ($btracker) {
806                     $mail->Body .= "<br /><br /><a href='". $tracker_url ."'>" . $tracker_text . "</a><br /><br />";
807                 } else {
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);
813                     }
814                 }
815                 //END
816
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>";
820                 }
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}' />";
823
824                 $mail->AltBody = $template_data['body'];
825                 if ($btracker) {
826                     $mail->AltBody .="\n". $tracker_url;
827                 }
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";
830                 }
831
832             }
833
834                         // cn: bug 4684, handle attachments in email templates.
835                         $mail->handleAttachments($this->notes_array);
836                         $tmp_Subject = $mail->Subject;
837                         $mail->prepForOutbound();
838
839                 $success = $mail->Send();
840                 //Do not save the encoded subject.
841             $mail->Subject = $tmp_Subject;
842                         if($success ){
843                 $email_id=null;
844                 if ($save_emails==1) {
845                     $email_id=$this->create_indiv_email($module,$mail);
846                 } else {
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}>";
850
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,
857                                             $this->user_id,
858                                             $this->notes_array,
859                                             $macro_nv,
860                                             $this->newmessage,
861                                             $fromAddressName
862                      );
863                     $this->newmessage = false;
864                 }
865             }
866
867                         if ($success) {
868                                 $this->set_as_sent($module->email1, true, $email_id, 'Emails', 'targeted');
869                         } else {
870
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'])];
874                         }
875                     }
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'])];
879                         }
880                     }
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');
883                         }
884                 }else{
885             $success = false;
886             $this->target_tracker_key=create_guid();
887
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');
890                         } else {
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');
893                                 } else {
894                                         $this->set_as_sent($module->email1,true, null,null,'send error');
895                                 }
896                         }
897                 }
898
899                 return $success;
900         }
901
902         /*
903          * Validates the passed email address.
904          * Limitations of this algorithm: does not validate email addressess that end with .meuseum
905          *
906          */
907         function valid_email_address($email_address) {
908
909                 $email_address=trim($email_address);
910                 if (empty($email_address)) {
911                         return false;
912                 }
913
914                 $pattern='/[A-Z0-9\._%-]+@[A-Z0-9\.-]+\.[A-Za-z]{2,}$/i';
915                 $ret=preg_match($pattern, $email_address);
916                 echo $ret;
917                 if ($ret===false or $ret==0) {
918                         return false;
919                 }
920                 return true;
921         }
922
923     /*
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
927      *
928      */
929     function is_primary_email_address($bean){
930         $email_address=trim($bean->email1);
931
932         if (empty($email_address)) {
933             return false;
934         }
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)) {
941             return true;
942         }
943         return false;
944
945      }
946
947     function create_export_query(&$order_by, &$where)
948     {
949         $custom_join = $this->getCustomJoin(true, true, $where);
950         $query = "SELECT emailman.*";
951         $query .= $custom_join['select'];
952
953         $query .= " FROM emailman ";
954
955         $query .= $custom_join['join'];
956
957         $where_auto = "( emailman.deleted IS NULL OR emailman.deleted=0 )";
958
959         if($where != "")
960             $query .= "where ($where) AND ".$where_auto;
961         else
962             $query .= "where ".$where_auto;
963
964         $order_by = $this->process_order_by($order_by);
965         if (!empty($order_by)) {
966             $query .= ' ORDER BY ' . $order_by;
967         }
968
969         return $query;
970     }
971
972     /**
973      * Actuall deletes the emailman record
974      * @param int $id
975      */
976     public function mark_deleted($id)
977         {
978             $this->db->query("DELETE FROM {$this->table_name} WHERE id=".intval($id));
979         }
980 }