source: spip-zone/_plugins_/mailshot/trunk/bulkmailer/mandrill.php @ 68515

Last change on this file since 68515 was 68515, checked in by cedric@…, 7 years ago

moins de debug

File size: 13.3 KB
Line 
1<?php
2/**
3 * Plugin MailShot
4 * (c) 2012 Cedric Morin
5 * Licence GNU/GPL
6 */
7
8if (!defined('_ECRIRE_INC_VERSION')) return;
9include_spip("inc/config");
10include_spip("classes/facteur");
11include_spip("lib/mandrill-api-php/src/Mandrill");
12
13/**
14 * @param array $to_send
15 *   string email
16 *   string sujet
17 *   string html
18 *   string texte
19 * @param array $options
20 *   bool filtre_images
21 *   array smtp
22 *     string host
23 *     string port
24 *     string auth
25 *     string username
26 *     string password
27 *     string secure
28 *     string errorsto
29 *   string adresse_envoi_nom
30 *   string adresse_envoi_email
31 * @return Facteur
32 */
33function &bulkmailer_mandrill_dist($to_send,$options=array()){
34        static $config = null;
35        static $mailer_defaut;
36        if (is_null($config)){
37                $config = lire_config("mailshot/");
38                $mailer_defaut = charger_fonction("defaut","bulkmailer");
39        }
40
41        // on ecrase le smtp avec celui de la config
42        $options['sender_class'] = "FacteurMandrill";
43        return $mailer_defaut($to_send,$options);
44
45}
46
47/**
48 * Prendre en charge le webhook mandrill
49 *
50 * @param $arg
51 */
52function bulkmailer_mandrill_webhook_dist($arg){
53
54        if ($_SERVER['REQUEST_METHOD'] == 'HEAD'){
55                http_status(200);
56                exit;
57        }
58
59        $events = _request('mandrill_events');
60        spip_log("bulkmailer_mandrill_webhook_dist $events","mailshot");
61
62        include_spip("inc/json");
63        $events = json_decode($events, true);
64
65        #spip_log("bulkmailer_mandrill_webhook_dist ".var_export($events,true),"mailshot");
66
67        foreach ($events as $event){
68                $quoi = $event['event'];
69                if ($quoi=="open") $quoi=="read"; // open chez mandrill, read ici
70
71                $email = $event['msg']['email'];
72                $tags = $event['msg']['tags'];
73                if (count($tags)){
74                        $tracking_id = end($tags);
75                        spip_log("tracking $quoi $email $tracking_id",'mailshot');
76                        // appeler l'api webhook mailshot
77                        $feedback = charger_fonction("feedback","newsletter");
78                        $feedback($quoi,$email,$tracking_id);
79                }
80        }
81}
82
83
84/**
85 * Initialiser mandrill : declarer un webhook pour recuperer les retours sur bounce, reject, open, clic....
86 *
87 * @param int $id_mailshot
88 * @return bool
89 */
90function bulkmailer_mandrill_init_dist($id_mailshot=0){
91        $api_key = lire_config("mailshot/mandrill_api_key");
92        $mandrill = new Mandrill($api_key);
93
94        spip_log("bulkmailer_mandrill_init_dist $id_mailshot","mailshot");
95
96        //WARNING: this would prevent curl from detecting a 'man in the middle' attack
97        curl_setopt($mandrill->ch, CURLOPT_SSL_VERIFYHOST, 0);
98        curl_setopt($mandrill->ch, CURLOPT_SSL_VERIFYPEER, 0);
99
100        // recuperer les webhooks existants
101        try {
102                $list = $mandrill->webhooks->getList();
103        }
104        catch (Exception $e) {
105                spip_log($e="Mandrill Exception ".$e->getMessage(),"mailshot"._LOG_ERREUR);
106    return false;
107  }
108
109        // son webhook
110        $url = url_absolue(_DIR_RACINE."mailshot_webhook.api/mandrill/");
111        $url = url_absolue(_DIR_RACINE."mailshot_webhook.api/mandrill/","http://www.yterium.net/");
112        $events = array(/*"send",*/"hard_bounce", "soft_bounce", "open", "click", "spam", "reject");
113
114        // chercher si un webhook deja existant avec cette url, et si les events sont ok
115        if (count($list)){
116                foreach ($list as $l){
117                        if ($l['url']==$url){
118                                $e = $l['events'];
119                                if (!count(array_diff($e,$events)) AND !count(array_diff($events,$e)))
120                                        return true;
121
122                                // la liste des events est non ok : supprimer ce webhook
123                                try {
124                                        $mandrill->webhooks->delete($l['id']);
125                                }
126                                catch (Exception $e) {
127                                        spip_log($e="Mandrill Exception ".$e->getMessage(),"mailshot"._LOG_ERREUR);
128                            return false;
129                          }
130                        }
131                }
132        }
133
134        // donc on a pas de webhook pour ce site, on l'ajoute
135
136        if (count($events)){
137                try {
138                        $mandrill->webhooks->add($url,$events);
139                }
140                catch (Exception $e) {
141                        spip_log($e="Mandrill Exception ".$e->getMessage(),"mailshot"._LOG_ERREUR);
142            return false;
143          }
144
145                // Debug : on verifie
146                /*
147                try {
148                        $list = $mandrill->webhooks->getList();
149                }
150                catch (Exception $e) {
151                        spip_log($e="Mandrill Exception ".$e->getMessage(),"mailshot"._LOG_ERREUR);
152            return false;
153          }
154                */
155        }
156
157        return true;
158}
159
160
161class FacteurMandrill extends Facteur {
162
163        protected $message = array('to'=>array(),'headers'=>array());
164
165        protected function cleanAdress($address, $name = ''){
166                $address = trim($address);
167    $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
168                if (!self::ValidateAddress($address)) {
169                        $this->SetError('invalid_address'.': '. $address);
170                        return false;
171          }
172                return array($address,$name);
173        }
174
175        /**
176        * Adds a "To" address.
177        * @param string $address
178        * @param string $name
179        * @return boolean true on success, false if address already used
180        */
181        public function AddAddress($address, $name = '') {
182                if ($a = $this->cleanAdress($address,$name)){
183                        $this->message['to'][] = array('email'=>$address,'name'=>$name);
184                        return true;
185                }
186                return false;
187        }
188
189        /**
190        * Adds a "Cc" address.
191        * Note: this function works with the SMTP mailer on win32, not with the "mail" mailer.
192        * @param string $address
193        * @param string $name
194        * @return boolean true on success, false if address already used
195        */
196        public function AddCC($address, $name = '') {
197                return $this->AddAddress($address, $name);
198        }
199
200        /**
201        * Adds a "Bcc" address.
202        * Note: this function works with the SMTP mailer on win32, not with the "mail" mailer.
203        * @param string $address
204        * @param string $name
205        * @return boolean true on success, false if address already used
206        */
207        public function AddBCC($address, $name = '') {
208                if ($a = $this->cleanAdress($address,$name)){
209                        $this->message['bcc_address'] = $address;
210                        return true;
211                }
212                return false;
213        }
214
215        /**
216        * Adds a "Reply-to" address.
217        * @param string $address
218        * @param string $name
219        * @return boolean
220        */
221        public function AddReplyTo($address, $name = '') {
222                if ($a = $this->cleanAdress($address,$name)){
223                        $this->message['headers']['ReplyTo'] = $address;
224                        return true;
225                }
226                return false;
227        }
228
229        /**
230        * Adds a custom header.
231        * @access public
232        * @return void
233        */
234        public function AddCustomHeader($custom_header) {
235                list($key,$value) = explode(':', $custom_header, 2);
236                $this->message['headers'][$key] = trim($value);
237        }
238
239        /**
240         * @param array $options
241         *   options d'envoi
242         *     string tracking_id
243         * @return bool
244         */
245        public function Send($options) {
246                $api_key = lire_config("mailshot/mandrill_api_key");
247
248                /**
249   * Send a new transactional message through Mandrill
250   * @param struct $message the information on the message to send
251   *     - html string the full HTML content to be sent
252   *     - text string optional full text content to be sent
253   *     - subject string the message subject
254   *     - from_email string the sender email address.
255   *     - from_name string optional from name to be used
256   *     - to array an array of recipient information.
257   *         - to[] struct a single recipient's information.
258   *             - email string the email address of the recipient
259   *             - name string the optional display name to use for the recipient
260   *     - headers struct optional extra headers to add to the message (currently only Reply-To and X-* headers are allowed)
261   *     - track_opens boolean whether or not to turn on open tracking for the message
262   *     - track_clicks boolean whether or not to turn on click tracking for the message
263   *     - auto_text boolean whether or not to automatically generate a text part for messages that are not given text
264   *     - url_strip_qs boolean whether or not to strip the query string from URLs when aggregating tracked URL data
265   *     - preserve_recipients boolean whether or not to expose all recipients in to "To" header for each email
266   *     - bcc_address string an optional address to receive an exact copy of each recipient's email
267   *     - merge boolean whether to evaluate merge tags in the message. Will automatically be set to true if either merge_vars or global_merge_vars are provided.
268   *     - global_merge_vars array global merge variables to use for all recipients. You can override these per recipient.
269   *         - global_merge_vars[] struct a single global merge variable
270   *             - name string the global merge variable's name. Merge variable names are case-insensitive and may not start with _
271   *             - content string the global merge variable's content
272   *     - merge_vars array per-recipient merge variables, which override global merge variables with the same name.
273   *         - merge_vars[] struct per-recipient merge variables
274   *             - rcpt string the email address of the recipient that the merge variables should apply to
275   *             - vars array the recipient's merge variables
276   *                 - vars[] struct a single merge variable
277   *                     - name string the merge variable's name. Merge variable names are case-insensitive and may not start with _
278   *                     - content string the merge variable's content
279   *     - tags array an array of string to tag the message with.  Stats are accumulated using tags, though we only store the first 100 we see, so this should not be unique or change frequently.  Tags should be 50 characters or less.  Any tags starting with an underscore are reserved for internal use and will cause errors.
280   *         - tags[] string a single tag - must not start with an underscore
281   *     - google_analytics_domains array an array of strings indicating for which any matching URLs will automatically have Google Analytics parameters appended to their query string automatically.
282   *     - google_analytics_campaign array|string optional string indicating the value to set for the utm_campaign tracking parameter. If this isn't provided the email's from address will be used instead.
283   *     - metadata array metadata an associative array of user metadata. Mandrill will store this metadata and make it available for retrieval. In addition, you can select up to 10 metadata fields to index and make searchable using the Mandrill search api.
284   *     - recipient_metadata array Per-recipient metadata that will override the global values specified in the metadata parameter.
285   *         - recipient_metadata[] struct metadata for a single recipient
286   *             - rcpt string the email address of the recipient that the metadata is associated with
287   *             - values array an associated array containing the recipient's unique metadata. If a key exists in both the per-recipient metadata and the global metadata, the per-recipient metadata will be used.
288   *     - attachments array an array of supported attachments to add to the message
289   *         - attachments[] struct a single supported attachment
290   *             - type string the MIME type of the attachment - allowed types are text/*, image/*, and application/pdf
291   *             - name string the file name of the attachment
292   *             - content string the content of the attachment as a base64-encoded string
293   * @param boolean $async enable a background sending mode that is optimized for bulk sending. In async mode, messages/send will immediately return a status of "queued" for every recipient. To handle rejections when sending in async mode, set up a webhook for the 'reject' event. Defaults to false for messages with fewer than 100 recipients; messages with more than 100 recipients are always sent asynchronously, regardless of the value of async.
294   * @return array of structs for each recipient containing the key "email" with the email address and "status" as either "sent", "queued", or "rejected"
295   *     - return[] struct the sending results for a single recipient
296   *         - email string the email address of the recipient
297   *         - status string the sending status of the recipient - either "sent", "queued", "rejected", or "invalid"
298   */
299                $this->message['html'] = $this->Body;
300                $this->message['text'] = $this->AltBody;
301                $this->message['subject'] = $this->Subject;
302                $this->message['from_email'] = $this->From;
303                $this->message['from_name'] = $this->FromName;
304
305                // ajouter le tracking_id en tag, pour retrouver le message apres webhook
306                if (isset($options['tracking_id'])
307                  AND $id = $options['tracking_id']){
308                        $this->message['tags'][] = $options['tracking_id'];
309                }
310
311                $mandrill = new Mandrill($api_key);
312
313                //WARNING: this would prevent curl from detecting a 'man in the middle' attack
314                curl_setopt($mandrill->ch, CURLOPT_SSL_VERIFYHOST, 0);
315                curl_setopt($mandrill->ch, CURLOPT_SSL_VERIFYPEER, 0);
316
317                try {
318                        $res = $mandrill->messages->send($this->message, false);
319                }
320                catch (Exception $e) {
321      $this->SetError($e->getMessage());
322      return false;
323    }
324
325                spip_log("FacteurMandrill->Send resultat:".var_export($res,true),"mailshot");
326
327                // statut d'erreur au premier niveau ?
328                if (isset($res['status'])){
329                        switch ($res['status']){
330                                case 'error':
331                                        $this->SetError($res['name'].": ".$res['message']);
332                                        return false;
333                                        break;
334                                default:
335                                        $this->SetError("??????".var_export($res,true));
336                                        return false;
337                                        break;
338                        }
339                }
340
341                // sinon regarder le status du premier mail envoye (le to)
342                // ici on ne gere qu'un destinataire
343                $rmail = reset($res);
344                switch ($rmail['status']){
345                        case 'invalid':
346                                $this->SetError("invalid");
347                                return false;
348                                break;
349                        case 'rejected':
350                                $this->SetError("rejected");
351                                return false;
352                                break;
353                        case "sent":
354                        case "queued":
355                                return true;
356                                break;
357                }
358
359                // ici on ne sait pas ce qu'il s'est passe !
360                $this->SetError("??????".var_export($res,true));
361                spip_log("FacteurMandrill->Send resultat inatendu : ".var_export($res,true),"mailshot"._LOG_ERREUR);
362                return false;
363
364        }
365
366        public function CreateHeader(){}
367}
Note: See TracBrowser for help on using the repository browser.