]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - modules/Campaigns/ProcessBouncedEmails.php
Release 6.5.6
[Github/sugarcrm.git] / modules / Campaigns / ProcessBouncedEmails.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-2012 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  * Description:
41  ********************************************************************************/
42 //find all mailboxes of type bounce.
43
44 /**
45  * Retrieve the attached error report for a bounced email if it exists.
46  *
47  * @param Email $email
48  * @return string
49  */
50 function retrieveErrorReportAttachment($email)
51 {
52     $contents = "";
53     $query = "SELECT description FROM notes WHERE file_mime_type = 'messsage/rfc822' AND parent_type='Emails' AND parent_id = '".$email->id."' AND deleted=0";
54     $rs = $GLOBALS['db']->query($query);
55     while ($row = $GLOBALS['db']->fetchByAssoc($rs)) 
56                 $contents .= $row['description'];
57
58     return $contents;
59 }
60
61 /**
62  * Create a bounced log campaign entry
63  *
64  * @param array $row
65  * @param Email $email
66  * @param string $email_description
67  * @return string
68  */
69 function createBouncedCampaignLogEntry($row,$email, $email_description)
70 {
71     $GLOBALS['log']->debug("Creating bounced email campaign log");
72     $bounce = new CampaignLog();
73     $bounce->campaign_id=$row['campaign_id'];
74     $bounce->target_tracker_key=$row['target_tracker_key'];
75     $bounce->target_id= $row['target_id'];
76     $bounce->target_type=$row['target_type'];
77     $bounce->list_id=$row['list_id'];
78     $bounce->marketing_id=$row['marketing_id'];
79
80     $bounce->activity_date=$email->date_created;
81     $bounce->related_type='Emails';
82     $bounce->related_id= $email->id;
83
84     //do we have the phrase permanent error in the email body.
85     if (preg_match('/permanent[ ]*error/',$email_description))
86     {
87         $bounce->activity_type='invalid email';
88         markEmailAddressInvalid($email);
89     }
90     else 
91         $bounce->activity_type='send error';
92         
93     $return_id=$bounce->save();
94     return $return_id;
95 }
96
97 /**
98  * Given an email address, mark it as invalid.
99  *
100  * @param $email_address
101  */
102 function markEmailAddressInvalid($email_address)
103 {
104     if(empty($email_address))
105         return;
106     $sea = new SugarEmailAddress();
107     $rs = $sea->retrieve_by_string_fields( array('email_address_caps' => trim(strtoupper($email_address))) );
108     if($rs != null)
109     {
110         $sea->AddUpdateEmailAddress($email_address, 1, 0, $rs->id);
111     }
112 }
113
114 /**
115  * Get the existing campaign log entry by tracker key.
116  * 
117  * @param string Target Key
118  * @return array Campaign Log Row
119  */
120 function getExistingCampaignLogEntry($identifier)
121 {
122     $row = FALSE;
123     $targeted = new CampaignLog();
124     $where="campaign_log.activity_type='targeted' and campaign_log.target_tracker_key='{$identifier}'";
125     $query=$targeted->create_new_list_query('',$where);
126     $result=$targeted->db->query($query);
127     $row=$targeted->db->fetchByAssoc($result);
128     
129     return $row;
130 }
131
132 /**
133  * Scan the bounced email searching for a valid target identifier.
134  * 
135  * @param string Email Description
136  * @return array Results including matches and identifier
137  */
138 function checkBouncedEmailForIdentifier($email_description)
139 {
140     $matches = array();
141     $identifiers = array();
142     $found = FALSE;
143     //Check if the identifier is present in the header.
144     if(preg_match('/X-CampTrackID: [a-z0-9\-]*/',$email_description,$matches)) 
145     {
146         $identifiers = preg_split('/X-CampTrackID: /',$matches[0],-1,PREG_SPLIT_NO_EMPTY);
147         $found = TRUE;
148         $GLOBALS['log']->debug("Found campaign identifier in header of email");  
149     }
150     else if( preg_match('/index.php\?entryPoint=removeme&identifier=[a-z0-9\-]*/',$email_description, $matches) )
151     {
152         $identifiers = preg_split('/index.php\?entryPoint=removeme&identifier=/',$matches[0],-1,PREG_SPLIT_NO_EMPTY);
153         $found = TRUE;
154         $GLOBALS['log']->debug("Found campaign identifier in body of email");
155     }
156     
157     return array('found' => $found, 'matches' => $matches, 'identifiers' => $identifiers);
158 }
159
160 function campaign_process_bounced_emails(&$email, &$email_header) 
161 {
162         global $sugar_config;
163         $emailFromAddress = $email_header->fromaddress;
164         $email_description = $email->raw_source;
165         
166         //if raw_source is empty, try using the description instead
167         if (empty($email_description)){
168                 $email_description = $email->description;
169         }
170
171     $email_description .= retrieveErrorReportAttachment($email);
172
173         if (preg_match('/MAILER-DAEMON|POSTMASTER/i',$emailFromAddress)) 
174         {
175             $email_description=quoted_printable_decode($email_description);
176                 $matches=array();
177                 
178                 //do we have the identifier tag in the email?
179                 $identifierScanResults = checkBouncedEmailForIdentifier($email_description);
180                 
181                 if ( $identifierScanResults['found'] ) 
182                 {
183                         $matches = $identifierScanResults['matches'];
184                         $identifiers = $identifierScanResults['identifiers'];
185
186                         if (!empty($identifiers)) 
187                         {
188                                 //array should have only one element in it.
189                                 $identifier = trim($identifiers[0]);
190                                 $row = getExistingCampaignLogEntry($identifier);
191                                 
192                                 //Found entry
193                                 if (!empty($row)) 
194                                 {
195                                         //do not create another campaign_log record is we already have an
196                                         //invalid email or send error entry for this tracker key.
197                                         $query_log = "select * from campaign_log where target_tracker_key='{$row['target_tracker_key']}'"; 
198                                         $query_log .=" and (activity_type='invalid email' or activity_type='send error')";
199                     $targeted = new CampaignLog();
200                                         $result_log=$targeted->db->query($query_log);
201                                         $row_log=$targeted->db->fetchByAssoc($result_log);
202
203                                         if (empty($row_log)) 
204                                         {
205                                                 $return_id = createBouncedCampaignLogEntry($row, $email, $email_description);   
206                                                 return TRUE;
207                                         }                               
208                                         else 
209                                         {
210                                             $GLOBALS['log']->debug("Warning: campaign log entry already exists for identifier $identifier");
211                                             return FALSE;
212                                         }
213                                 } 
214                                 else 
215                                 {
216                                     $GLOBALS['log']->info("Warning: skipping bounced email with this tracker_key(identifier) in the message body: ".$identifier);
217                                         return FALSE;
218                                 }                       
219                 } 
220                 else 
221                 {
222                         $GLOBALS['log']->info("Warning: Empty identifier for campaign log.");
223                         return FALSE;
224                 }
225         }  
226         else 
227         {
228             $GLOBALS['log']->info("Warning: skipping bounced email because it does not have the removeme link.");       
229                 return FALSE;   
230         }
231   } 
232   else 
233   {
234         $GLOBALS['log']->info("Warning: skipping bounced email because the sender is not MAILER-DAEMON.");
235         return FALSE;
236   }
237 }
238 ?>