dolibarr 20.0.5
CMailFile.class.php
Go to the documentation of this file.
1<?php
35use OAuth\Common\Storage\DoliStorage;
36use OAuth\Common\Consumer\Credentials;
37
38
45{
46 public $sendcontext;
47 public $sendmode;
48 public $sendsetup;
49
53 public $subject;
54 public $addr_from; // From: Label and EMail of sender (must include '<>'). For example '<myemail@example.com>' or 'John Doe <myemail@example.com>' or '<myemail+trackingid@example.com>'). Note that with gmail smtps, value here is forced by google to account (but not the reply-to).
55 // Sender: Who send the email ("Sender" has sent emails on behalf of "From").
56 // Use it when the "From" is an email of a domain that is a SPF protected domain, and the sending smtp server is not this domain. In such case, add Sender field with an email of the protected domain.
57 // Return-Path: Email where to send bounds.
58 public $reply_to; // Reply-To: Email where to send replies from mailer software (mailer use From if reply-to not defined, Gmail use gmail account if reply-to not defined)
59 public $errors_to; // Errors-To: Email where to send errors.
60 public $addr_to;
61 public $addr_cc;
62 public $addr_bcc;
63 public $trackid;
64
65 public $mixed_boundary;
66 public $related_boundary;
67 public $alternative_boundary;
68 public $deliveryreceipt;
69
70 public $atleastonefile;
71
72 public $msg;
73 public $eol;
74 public $eol2;
75
79 public $error = '';
80
84 public $errors = array();
85
86
90 public $smtps;
94 public $mailer;
95
99 public $transport;
103 public $logger;
104
108 public $css;
110 public $styleCSS;
112 public $bodyCSS;
113
117 public $msgid;
118
122 public $in_reply_to;
123
127 public $references;
128
129 public $headers;
130
131 public $message;
132
136 public $filename_list = array();
140 public $mimetype_list = array();
144 public $mimefilename_list = array();
148 public $cid_list = array();
149
150 // Image
151 public $html;
152 public $msgishtml;
153 public $image_boundary;
154 public $atleastoneimage = 0; // at least one image file with file=xxx.ext into content (TODO Debug this. How can this case be tested. Remove if not used).
155 public $html_images = array();
156 public $images_encoded = array();
157 public $image_types = array(
158 'gif' => 'image/gif',
159 'jpg' => 'image/jpeg',
160 'jpeg' => 'image/jpeg',
161 'jpe' => 'image/jpeg',
162 'bmp' => 'image/bmp',
163 'png' => 'image/png',
164 'tif' => 'image/tiff',
165 'tiff' => 'image/tiff',
166 );
167
168
193 public function __construct($subject, $to, $from, $msg, $filename_list = array(), $mimetype_list = array(), $mimefilename_list = array(), $addr_cc = "", $addr_bcc = "", $deliveryreceipt = 0, $msgishtml = 0, $errors_to = '', $css = '', $trackid = '', $moreinheader = '', $sendcontext = 'standard', $replyto = '', $upload_dir_tmp = '', $in_reply_to = '', $references = '')
194 {
195 global $conf, $dolibarr_main_data_root, $user;
196
197 dol_syslog("CMailFile::CMailfile: charset=".$conf->file->character_set_client." from=$from, to=$to, addr_cc=$addr_cc, addr_bcc=$addr_bcc, errors_to=$errors_to, replyto=$replyto trackid=$trackid sendcontext=$sendcontext");
198 dol_syslog("CMailFile::CMailfile: subject=".$subject.", deliveryreceipt=".$deliveryreceipt.", msgishtml=".$msgishtml, LOG_DEBUG);
199
200
201 // Clean values of $mimefilename_list
202 if (is_array($mimefilename_list)) {
203 foreach ($mimefilename_list as $key => $val) {
204 $mimefilename_list[$key] = dol_string_unaccent($mimefilename_list[$key]);
205 }
206 }
207
208 $cid_list = array();
209
210 $this->sendcontext = $sendcontext;
211
212 // Define this->sendmode ('mail', 'smtps', 'swiftmailer', ...) according to $sendcontext ('standard', 'emailing', 'ticket', 'passwordreset')
213 $this->sendmode = '';
214 if (!empty($this->sendcontext)) {
215 $smtpContextKey = strtoupper($this->sendcontext);
216 $smtpContextSendMode = getDolGlobalString('MAIN_MAIL_SENDMODE_'.$smtpContextKey);
217 if (!empty($smtpContextSendMode) && $smtpContextSendMode != 'default') {
218 $this->sendmode = $smtpContextSendMode;
219 }
220 }
221 if (empty($this->sendmode)) {
222 $this->sendmode = getDolGlobalString('MAIN_MAIL_SENDMODE', 'mail');
223 }
224
225 // Add a Feedback-ID. Must be used for stats on spam report only.
226 if ($trackid) {
227 //Examples:
228 // LinkedIn – Feedback-ID: accept_invite_04:linkedin
229 // Twitter – Feedback-ID: 0040162518f58f41d1f0:15491f3b2ee48656f8e7fb2fac:none:twitterESP
230 // Amazon.com : Feedback-ID: 1.eu-west-1.kjoQSiqb8G+7lWWiDVsxjM2m0ynYd4I6yEFlfoox6aY=:AmazonSES
231 $moreinheader .= "Feedback-ID: ".$trackid.':'.dol_getprefix('email').":dolib\r\n";
232 }
233
234 // We define end of line (RFC 821).
235 $this->eol = "\r\n";
236 // We define end of line for header fields (RFC 822bis section 2.3 says header must contains \r\n).
237 $this->eol2 = "\r\n";
238 if (getDolGlobalString('MAIN_FIX_FOR_BUGGED_MTA')) {
239 $this->eol = "\n";
240 $this->eol2 = "\n";
241 $moreinheader = str_replace("\r\n", "\n", $moreinheader);
242 }
243
244 // On defini mixed_boundary
245 $this->mixed_boundary = "multipart_x.".time().".x_boundary";
246
247 // On defini related_boundary
248 $this->related_boundary = 'mul_'.dol_hash(uniqid("dolibarr2"), 3); // Force md5 hash (does not contain special chars)
249
250 // On defini alternative_boundary
251 $this->alternative_boundary = 'mul_'.dol_hash(uniqid("dolibarr3"), 3); // Force md5 hash (does not contain special chars)
252
253 if (empty($subject)) {
254 dol_syslog("CMailFile::CMailfile: Try to send an email with empty subject");
255 $this->error = 'ErrorSubjectIsRequired';
256 return;
257 }
258 if (empty($msg)) {
259 dol_syslog("CMailFile::CMailfile: Try to send an email with empty body");
260 $msg = '.'; // Avoid empty message (with empty message content, you will see a multipart structure)
261 }
262
263 // Detect if message is HTML (use fast method)
264 if ($msgishtml == -1) {
265 $this->msgishtml = 0;
266 if (dol_textishtml($msg)) {
267 $this->msgishtml = 1;
268 }
269 } else {
270 $this->msgishtml = $msgishtml;
271 }
272
273 global $dolibarr_main_url_root;
274
275 // Define $urlwithroot
276 $urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($dolibarr_main_url_root));
277 $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file
278 //$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current
279
280 // Replace relative /viewimage to absolute path
281 $msg = preg_replace('/src="'.preg_quote(DOL_URL_ROOT, '/').'\/viewimage\.php/ims', 'src="'.$urlwithroot.'/viewimage.php', $msg, -1);
282
283 if (getDolGlobalString('MAIN_MAIL_FORCE_CONTENT_TYPE_TO_HTML')) {
284 $this->msgishtml = 1; // To force to send everything with content type html.
285 }
286 dol_syslog("CMailFile::CMailfile: msgishtml=".$this->msgishtml, LOG_DEBUG);
287
288 // Detect images
289 if ($this->msgishtml) {
290 $this->html = $msg;
291
292 $findimg = 0;
293 if (getDolGlobalString('MAIN_MAIL_ADD_INLINE_IMAGES_IF_IN_MEDIAS')) { // Off by default
294 // Search into the body for <img tags of links in medias files to replace them with an embedded file
295 // Note because media links are public, this should be useless, except avoid blocking images with email browser.
296 // This converts an embed file with src="/viewimage.php?modulepart... into a cid link
297 // TODO Exclude viewimage used for the read tracker ?
298 $dolibarr_main_data_root_images = $dolibarr_main_data_root;
299 if ((int) $conf->entity !== 1) {
300 $dolibarr_main_data_root_images.='/'.$conf->entity.'/';
301 }
302 $findimg = $this->findHtmlImages($dolibarr_main_data_root_images.'/medias');
303 if ($findimg < 0) {
304 dol_syslog("CMailFile::CMailfile: Error on findHtmlImages");
305 $this->error = 'ErrorInAddAttachmentsImageBaseOnMedia';
306 return;
307 }
308 }
309
310 if (getDolGlobalString('MAIN_MAIL_ADD_INLINE_IMAGES_IF_DATA')) {
311 // Search into the body for <img src="data:image/ext;base64,..." to replace them with an embedded file
312 // This convert an embedded file with src="data:image... into a cid link + attached file
313 $resultImageData = $this->findHtmlImagesIsSrcData($upload_dir_tmp);
314 if ($resultImageData < 0) {
315 dol_syslog("CMailFile::CMailfile: Error on findHtmlImagesInSrcData code=".$resultImageData." upload_dir_tmp=".$upload_dir_tmp);
316 $this->error = 'ErrorInAddAttachmentsImageBaseIsSrcData';
317 return;
318 }
319 $findimg += $resultImageData;
320 }
321
322 // Set atleastoneimage if there is at least one embedded file (into ->html_images)
323 if ($findimg > 0) {
324 foreach ($this->html_images as $i => $val) {
325 if ($this->html_images[$i]) {
326 $this->atleastoneimage = 1;
327 if ($this->html_images[$i]['type'] == 'cidfromdata') {
328 if (!in_array($this->html_images[$i]['fullpath'], $filename_list)) {
329 // If this file path is not already into the $filename_list, we append it at end of array
330 $posindice = count($filename_list);
331 $filename_list[$posindice] = $this->html_images[$i]['fullpath'];
332 $mimetype_list[$posindice] = $this->html_images[$i]['content_type'];
333 $mimefilename_list[$posindice] = $this->html_images[$i]['name'];
334 } else {
335 $posindice = array_search($this->html_images[$i]['fullpath'], $filename_list);
336 }
337 // We complete the array of cid_list
338 $cid_list[$posindice] = $this->html_images[$i]['cid'];
339 }
340 dol_syslog("CMailFile::CMailfile: html_images[$i]['name']=".$this->html_images[$i]['name'], LOG_DEBUG);
341 }
342 }
343 }
344 }
345 //var_dump($filename_list);
346 //var_dump($cid_list);exit;
347
348 // Set atleastoneimage if there is at least one file (into $filename_list array)
349 if (is_array($filename_list)) {
350 foreach ($filename_list as $i => $val) {
351 if ($filename_list[$i]) {
352 $this->atleastonefile = 1;
353 dol_syslog("CMailFile::CMailfile: filename_list[$i]=".$filename_list[$i].", mimetype_list[$i]=".$mimetype_list[$i]." mimefilename_list[$i]=".$mimefilename_list[$i]." cid_list[$i]=".(empty($cid_list[$i]) ? '' : $cid_list[$i]), LOG_DEBUG);
354 }
355 }
356 }
357
358 // Add auto copy to if not already in $to (Note: Adding bcc for specific modules are also done from pages)
359 // For example MAIN_MAIL_AUTOCOPY_TO can be 'email@example.com, __USER_EMAIL__, ...'
360 if (getDolGlobalString('MAIN_MAIL_AUTOCOPY_TO')) {
361 $listofemailstoadd = explode(',', getDolGlobalString('MAIN_MAIL_AUTOCOPY_TO'));
362 foreach ($listofemailstoadd as $key => $val) {
363 $emailtoadd = $listofemailstoadd[$key];
364 if (trim($emailtoadd) == '__USER_EMAIL__') {
365 if (!empty($user) && !empty($user->email)) {
366 $emailtoadd = $user->email;
367 } else {
368 $emailtoadd = '';
369 }
370 }
371 if ($emailtoadd && preg_match('/'.preg_quote($emailtoadd, '/').'/i', $to)) {
372 $emailtoadd = ''; // Email already in the "To"
373 }
374 if ($emailtoadd) {
375 $listofemailstoadd[$key] = $emailtoadd;
376 } else {
377 unset($listofemailstoadd[$key]);
378 }
379 }
380 if (!empty($listofemailstoadd)) {
381 $addr_bcc .= ($addr_bcc ? ', ' : '').implode(', ', $listofemailstoadd);
382 }
383 }
384
385 // Verify if $to, $addr_cc and addr_bcc have unwanted addresses
386 if (getDolGlobalString('MAIN_MAIL_FORCE_NOT_SENDING_TO')) {
387 // Parse to, cc and bcc to remove MAIN_MAIL_FORCE_NOT_SENDING_TO
388 $listofemailstonotsendto = explode(',', getDolGlobalString('MAIN_MAIL_FORCE_NOT_SENDING_TO'));
389
390 //Verify for $to
391 $replaceto = false;
392 $tabto = explode(",", $to);
393 foreach ($tabto as $key => $addrto) {
394 $addrto = array_keys($this->getArrayAddress($addrto));
395 if (in_array($addrto[0], $listofemailstonotsendto)) {
396 unset($tabto[$key]);
397 $replaceto = true;
398 }
399 }
400 if ($replaceto && getDolGlobalString('MAIN_MAIL_FORCE_NOT_SENDING_TO_REPLACE')) {
401 $tabto[] = getDolGlobalString('MAIN_MAIL_FORCE_NOT_SENDING_TO_REPLACE');
402 }
403 $to = implode(',', $tabto);
404
405 //Verify for $addr_cc
406 $replacecc = false;
407 $tabcc = explode(',', $addr_cc);
408 foreach ($tabcc as $key => $cc) {
409 $cc = array_keys($this->getArrayAddress($cc));
410 if (in_array($cc[0], $listofemailstonotsendto)) {
411 unset($tabcc[$key]);
412 $replacecc = true;
413 }
414 }
415 if ($replacecc && getDolGlobalString('MAIN_MAIL_FORCE_NOT_SENDING_TO_REPLACE')) {
416 $tabcc[] = getDolGlobalString('MAIN_MAIL_FORCE_NOT_SENDING_TO_REPLACE');
417 }
418 $addr_cc = implode(',', $tabcc);
419
420 //Verify for $addr_bcc
421 $replacebcc = false;
422 $tabbcc = explode(',', $addr_bcc);
423 foreach ($tabbcc as $key => $bcc) {
424 $bcc = array_keys($this->getArrayAddress($bcc));
425 if (in_array($bcc[0], $listofemailstonotsendto)) {
426 unset($tabbcc[$key]);
427 $replacebcc = true;
428 }
429 }
430 if ($replacebcc && getDolGlobalString('MAIN_MAIL_FORCE_NOT_SENDING_TO_REPLACE')) {
431 $tabbcc[] = getDolGlobalString('MAIN_MAIL_FORCE_NOT_SENDING_TO_REPLACE');
432 }
433 $addr_bcc = implode(',', $tabbcc);
434 }
435
436 // We always use a replyto
437 if (empty($replyto)) {
438 $replyto = dol_sanitizeEmail($from);
439 }
440 // We can force the from
441 if (getDolGlobalString('MAIN_MAIL_FORCE_FROM')) {
442 $from = getDolGlobalString('MAIN_MAIL_FORCE_FROM');
443 }
444
445 $this->subject = $subject;
446 $this->addr_to = dol_sanitizeEmail($to);
447 $this->addr_from = dol_sanitizeEmail($from);
448 $this->msg = $msg;
449 $this->addr_cc = dol_sanitizeEmail($addr_cc);
450 $this->addr_bcc = dol_sanitizeEmail($addr_bcc);
451 $this->deliveryreceipt = $deliveryreceipt;
452 $this->reply_to = dol_sanitizeEmail($replyto);
453 $this->errors_to = dol_sanitizeEmail($errors_to);
454 $this->trackid = $trackid;
455 $this->in_reply_to = $in_reply_to;
456 $this->references = $references;
457 // Set arrays with attached files info
458 $this->filename_list = $filename_list;
459 $this->mimetype_list = $mimetype_list;
460 $this->mimefilename_list = $mimefilename_list;
461 $this->cid_list = $cid_list;
462
463 if (getDolGlobalString('MAIN_MAIL_FORCE_SENDTO')) {
464 $this->addr_to = dol_sanitizeEmail(getDolGlobalString('MAIN_MAIL_FORCE_SENDTO'));
465 $this->addr_cc = '';
466 $this->addr_bcc = '';
467 }
468
469 $keyforsslseflsigned = 'MAIN_MAIL_EMAIL_SMTP_ALLOW_SELF_SIGNED';
470 if (!empty($this->sendcontext)) {
471 $smtpContextKey = strtoupper($this->sendcontext);
472 $smtpContextSendMode = getDolGlobalString('MAIN_MAIL_SENDMODE_'.$smtpContextKey);
473 if (!empty($smtpContextSendMode) && $smtpContextSendMode != 'default') {
474 $keyforsslseflsigned = 'MAIN_MAIL_EMAIL_SMTP_ALLOW_SELF_SIGNED_'.$smtpContextKey;
475 }
476 }
477
478 dol_syslog("CMailFile::CMailfile: sendmode=".$this->sendmode." addr_bcc=$addr_bcc, replyto=$replyto", LOG_DEBUG);
479
480 // We set all data according to chose sending method.
481 // We also set a value for ->msgid
482 if ($this->sendmode == 'mail') {
483 // Use mail php function (default PHP method)
484 // ------------------------------------------
485
486 $smtp_headers = "";
487 $mime_headers = "";
488 $text_body = "";
489 $files_encoded = "";
490
491 // Define smtp_headers (this also set SMTP headers from ->msgid, ->in_reply_to and ->references)
492 $smtp_headers = $this->write_smtpheaders();
493 if (!empty($moreinheader)) {
494 $smtp_headers .= $moreinheader; // $moreinheader contains the \r\n
495 }
496
497 // Define mime_headers
498 $mime_headers = $this->write_mimeheaders($filename_list, $mimefilename_list);
499
500 if (!empty($this->html)) {
501 if (!empty($css)) {
502 $this->css = $css;
503 $this->buildCSS(); // Build a css style (mode = all) into this->styleCSS and this->bodyCSS
504 }
505
506 $msg = $this->html;
507 }
508
509 // Define body in text_body
510 $text_body = $this->write_body($msg);
511
512 // Add attachments to text_encoded
513 if (!empty($this->atleastonefile)) {
514 $files_encoded = $this->write_files($filename_list, $mimetype_list, $mimefilename_list, $cid_list);
515 }
516
517 // We now define $this->headers and $this->message
518 $this->headers = $smtp_headers.$mime_headers;
519 // Clean the header to avoid that it terminates with a CR character.
520 // This avoid also empty lines at end that can be interpreted as mail injection by email servers.
521 $this->headers = preg_replace("/([\r\n]+)$/i", "", $this->headers);
522
523 //$this->message = $this->eol.'This is a message with multiple parts in MIME format.'.$this->eol;
524 $this->message = 'This is a message with multiple parts in MIME format.'.$this->eol;
525 $this->message .= $text_body.$files_encoded;
526 $this->message .= "--".$this->mixed_boundary."--".$this->eol;
527 } elseif ($this->sendmode == 'smtps') {
528 // Use SMTPS library
529 // ------------------------------------------
530 $host = dol_getprefix('email');
531
532 require_once DOL_DOCUMENT_ROOT.'/core/class/smtps.class.php';
533 $smtps = new SMTPs();
534 $smtps->setCharSet($conf->file->character_set_client);
535
536 // Encode subject if required.
537 $subjecttouse = $this->subject;
538 if (!ascii_check($subjecttouse)) {
539 $subjecttouse = $this->encodetorfc2822($subjecttouse);
540 }
541
542 $smtps->setSubject($subjecttouse);
543 $smtps->setTO($this->getValidAddress($this->addr_to, 0, 1));
544 $smtps->setFrom($this->getValidAddress($this->addr_from, 0, 1));
545 $smtps->setReplyTo($this->getValidAddress($this->reply_to, 0, 1));
546
547 $smtps->setTrackId($this->trackid);
548
549 if (!empty($this->in_reply_to)) {
550 $smtps->setInReplyTo($this->in_reply_to);
551 }
552 if (!empty($this->references)) {
553 $smtps->setReferences($this->references);
554 }
555
556 if (!empty($moreinheader)) {
557 $smtps->setMoreInHeader($moreinheader);
558 }
559
560 //X-Dolibarr-TRACKID, In-Reply-To, References and $moreinheader will be added to header inside the smtps->getHeader
561
562 if (!empty($this->html)) {
563 if (!empty($css)) {
564 $this->css = $css;
565 $this->buildCSS();
566 }
567 $msg = $this->html;
568 $msg = $this->checkIfHTML($msg); // This add a header and a body including custom CSS to the HTML content
569 }
570
571 // Replace . alone on a new line with .. to avoid to have SMTP interpret this as end of message
572 $msg = preg_replace('/(\r|\n)\.(\r|\n)/ims', '\1..\2', $msg);
573
574 if ($this->msgishtml) {
575 $smtps->setBodyContent($msg, 'html');
576 } else {
577 $smtps->setBodyContent($msg, 'plain');
578 }
579
580 if ($this->atleastoneimage) {
581 foreach ($this->images_encoded as $img) {
582 $smtps->setImageInline($img['image_encoded'], $img['name'], $img['content_type'], $img['cid']);
583 }
584 }
585
586 if (!empty($this->atleastonefile)) {
587 foreach ($filename_list as $i => $val) {
588 $content = file_get_contents($filename_list[$i]);
589 if (empty($cid_list[$i])) {
590 $smtps->setAttachment($content, $mimefilename_list[$i], $mimetype_list[$i], (empty($cid_list[$i]) ? '' : $cid_list[$i]));
591 }
592 }
593 }
594
595 $smtps->setCC($this->addr_cc);
596 $smtps->setBCC($this->addr_bcc);
597 $smtps->setErrorsTo($this->errors_to);
598 $smtps->setDeliveryReceipt($this->deliveryreceipt);
599 if (getDolGlobalString($keyforsslseflsigned)) {
600 $smtps->setOptions(array('ssl' => array('verify_peer' => false, 'verify_peer_name' => false, 'allow_self_signed' => true)));
601 }
602
603 $this->msgid = time().'.SMTPs-dolibarr-'.$this->trackid.'@'.$host;
604
605 $this->smtps = $smtps;
606 } elseif ($this->sendmode == 'swiftmailer') {
607 // Use Swift Mailer library
608 // ------------------------------------------
609 $host = dol_getprefix('email');
610
611 require_once DOL_DOCUMENT_ROOT.'/includes/swiftmailer/lexer/lib/Doctrine/Common/Lexer/AbstractLexer.php';
612
613 // egulias autoloader lib
614 require_once DOL_DOCUMENT_ROOT.'/includes/swiftmailer/autoload.php';
615
616 require_once DOL_DOCUMENT_ROOT.'/includes/swiftmailer/lib/swift_required.php';
617
618 // Create the message
619 //$this->message = Swift_Message::newInstance();
620 $this->message = new Swift_Message();
621 //$this->message = new Swift_SignedMessage();
622 // Adding a trackid header to a message
623 $headers = $this->message->getHeaders();
624
625 $headers->addTextHeader('X-Dolibarr-TRACKID', $this->trackid.'@'.$host);
626 $this->msgid = time().'.swiftmailer-dolibarr-'.$this->trackid.'@'.$host;
627 $headerID = $this->msgid;
628 $msgid = $headers->get('Message-ID');
629 $msgid->setId($headerID);
630
631 // Add 'In-Reply-To:' header
632 if (!empty($this->in_reply_to)) {
633 $headers->addIdHeader('In-Reply-To', $this->in_reply_to);
634 }
635 // Add 'References:' header
636 if (!empty($this->references)) {
637 $headers->addIdHeader('References', $this->references);
638 }
639
640 if (!empty($moreinheader)) {
641 $moreinheaderarray = preg_split('/[\r\n]+/', $moreinheader);
642 foreach ($moreinheaderarray as $moreinheaderval) {
643 $moreinheadervaltmp = explode(':', $moreinheaderval, 2);
644 if (!empty($moreinheadervaltmp[0]) && !empty($moreinheadervaltmp[1])) {
645 $headers->addTextHeader($moreinheadervaltmp[0], $moreinheadervaltmp[1]);
646 }
647 }
648 }
649
650 // Give the message a subject
651 try {
652 $this->message->setSubject($this->subject);
653 } catch (Exception $e) {
654 $this->errors[] = $e->getMessage();
655 }
656
657 // Set the From address with an associative array
658 //$this->message->setFrom(array('john@doe.com' => 'John Doe'));
659 if (!empty($this->addr_from)) {
660 try {
661 if (getDolGlobalString('MAIN_FORCE_DISABLE_MAIL_SPOOFING')) {
662 // Prevent email spoofing for smtp server with a strict configuration
663 $regexp = '/([a-z0-9_\.\-\+])+\@(([a-z0-9\-])+\.)+([a-z0-9]{2,4})+/i'; // This regular expression extracts all emails from a string
664 $adressEmailFrom = array();
665 $emailMatchs = preg_match_all($regexp, $from, $adressEmailFrom);
666 $adressEmailFrom = reset($adressEmailFrom);
667 if ($emailMatchs !== false && filter_var(getDolGlobalString('MAIN_MAIL_SMTPS_ID'), FILTER_VALIDATE_EMAIL) && getDolGlobalString('MAIN_MAIL_SMTPS_ID') !== $adressEmailFrom[0]) {
668 $this->message->setFrom(getDolGlobalString('MAIN_MAIL_SMTPS_ID'));
669 } else {
670 $this->message->setFrom($this->getArrayAddress($this->addr_from));
671 }
672 } else {
673 $this->message->setFrom($this->getArrayAddress($this->addr_from));
674 }
675 } catch (Exception $e) {
676 $this->errors[] = $e->getMessage();
677 }
678 }
679
680 // Set the To addresses with an associative array
681 if (!empty($this->addr_to)) {
682 try {
683 $this->message->setTo($this->getArrayAddress($this->addr_to));
684 } catch (Exception $e) {
685 $this->errors[] = $e->getMessage();
686 }
687 }
688
689 if (!empty($this->reply_to)) {
690 try {
691 $this->message->SetReplyTo($this->getArrayAddress($this->reply_to));
692 } catch (Exception $e) {
693 $this->errors[] = $e->getMessage();
694 }
695 }
696
697 if (!empty($this->errors_to)) {
698 try {
699 $headers->addTextHeader('Errors-To', $this->getValidAddress($this->errors_to, 0));
700 } catch (Exception $e) {
701 $this->errors[] = $e->getMessage();
702 }
703 }
704
705 try {
706 $this->message->setCharSet($conf->file->character_set_client);
707 } catch (Exception $e) {
708 $this->errors[] = $e->getMessage();
709 }
710
711 if (!empty($this->html)) {
712 if (!empty($css)) {
713 $this->css = $css;
714 $this->buildCSS();
715 }
716 $msg = $this->html;
717 $msg = $this->checkIfHTML($msg); // This add a header and a body including custom CSS to the HTML content
718 }
719
720 if ($this->atleastoneimage) {
721 foreach ($this->html_images as $img) {
722 // $img['fullpath'],$img['image_encoded'],$img['name'],$img['content_type'],$img['cid']
723 $attachment = Swift_Image::fromPath($img['fullpath']);
724 // embed image
725 $imgcid = $this->message->embed($attachment);
726 // replace cid by the one created by swiftmail in html message
727 $msg = str_replace("cid:".$img['cid'], $imgcid, $msg);
728 }
729 foreach ($this->images_encoded as $img) {
730 //$img['fullpath'],$img['image_encoded'],$img['name'],$img['content_type'],$img['cid']
731 $attachment = Swift_Image::fromPath($img['fullpath']);
732 // embed image
733 $imgcid = $this->message->embed($attachment);
734 // replace cid by the one created by swiftmail in html message
735 $msg = str_replace("cid:".$img['cid'], $imgcid, $msg);
736 }
737 }
738
739 if ($this->msgishtml) {
740 $this->message->setBody($msg, 'text/html');
741 // And optionally an alternative body
742 $this->message->addPart(html_entity_decode(strip_tags($msg)), 'text/plain');
743 } else {
744 $this->message->setBody($msg, 'text/plain');
745 // And optionally an alternative body
746 $this->message->addPart(dol_nl2br($msg), 'text/html');
747 }
748
749 if (!empty($this->atleastonefile)) {
750 foreach ($filename_list as $i => $val) {
751 //$this->message->attach(Swift_Attachment::fromPath($filename_list[$i],$mimetype_list[$i]));
752 $attachment = Swift_Attachment::fromPath($filename_list[$i], $mimetype_list[$i]);
753 if (!empty($mimefilename_list[$i])) {
754 $attachment->setFilename($mimefilename_list[$i]);
755 }
756 $this->message->attach($attachment);
757 }
758 }
759
760 if (!empty($this->addr_cc)) {
761 try {
762 $this->message->setCc($this->getArrayAddress($this->addr_cc));
763 } catch (Exception $e) {
764 $this->errors[] = $e->getMessage();
765 }
766 }
767 if (!empty($this->addr_bcc)) {
768 try {
769 $this->message->setBcc($this->getArrayAddress($this->addr_bcc));
770 } catch (Exception $e) {
771 $this->errors[] = $e->getMessage();
772 }
773 }
774 if (isset($this->deliveryreceipt) && $this->deliveryreceipt == 1) {
775 try {
776 $this->message->setReadReceiptTo($this->getArrayAddress($this->addr_from));
777 } catch (Exception $e) {
778 $this->errors[] = $e->getMessage();
779 }
780 }
781 } else {
782 // Send mail method not correctly defined
783 // --------------------------------------
784 $this->error = 'Bad value for sendmode';
785 }
786 }
787
795 public function sendfile()
796 {
797 global $conf, $db, $langs, $hookmanager;
798
799 $errorlevel = error_reporting();
800 //error_reporting($errorlevel ^ E_WARNING); // Desactive warnings
801
802 $res = false;
803
804 if (!getDolGlobalString('MAIN_DISABLE_ALL_MAILS')) {
805 if (!is_object($hookmanager)) {
806 include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
807 $hookmanager = new HookManager($db);
808 }
809 $hookmanager->initHooks(array('mail'));
810
811 $parameters = array();
812 $action = '';
813 $reshook = $hookmanager->executeHooks('sendMail', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
814 if ($reshook < 0) {
815 $this->error = "Error in hook maildao sendMail ".$reshook;
816 dol_syslog("CMailFile::sendfile: mail end error=".$this->error, LOG_ERR);
817
818 return false;
819 }
820 if ($reshook == 1) { // Hook replace standard code
821 return true;
822 }
823
824 $sendingmode = $this->sendmode;
825 if ($this->sendcontext == 'emailing' && getDolGlobalString('MAILING_NO_USING_PHPMAIL') && $sendingmode == 'mail') {
826 // List of sending methods
827 $listofmethods = array();
828 $listofmethods['mail'] = 'PHP mail function';
829 //$listofmethods['simplemail']='Simplemail class';
830 $listofmethods['smtps'] = 'SMTP/SMTPS socket library';
831
832 // EMailing feature may be a spam problem, so when you host several users/instance, having this option may force each user to use their own SMTP agent.
833 // You ensure that every user is using its own SMTP server when using the mass emailing module.
834 $linktoadminemailbefore = '<a href="'.DOL_URL_ROOT.'/admin/mails.php">';
835 $linktoadminemailend = '</a>';
836 $this->error = $langs->trans("MailSendSetupIs", $listofmethods[$sendingmode]);
837 $this->errors[] = $langs->trans("MailSendSetupIs", $listofmethods[$sendingmode]);
838 $this->error .= '<br>'.$langs->trans("MailSendSetupIs2", $linktoadminemailbefore, $linktoadminemailend, $langs->transnoentitiesnoconv("MAIN_MAIL_SENDMODE"), $listofmethods['smtps']);
839 $this->errors[] = $langs->trans("MailSendSetupIs2", $linktoadminemailbefore, $linktoadminemailend, $langs->transnoentitiesnoconv("MAIN_MAIL_SENDMODE"), $listofmethods['smtps']);
840 if (getDolGlobalString('MAILING_SMTP_SETUP_EMAILS_FOR_QUESTIONS')) {
841 $this->error .= '<br>'.$langs->trans("MailSendSetupIs3", getDolGlobalString('MAILING_SMTP_SETUP_EMAILS_FOR_QUESTIONS'));
842 $this->errors[] = $langs->trans("MailSendSetupIs3", getDolGlobalString('MAILING_SMTP_SETUP_EMAILS_FOR_QUESTIONS'));
843 }
844
845 dol_syslog("CMailFile::sendfile: mail end error=".$this->error, LOG_WARNING);
846 return false;
847 }
848
849 // Check number of recipient is lower or equal than MAIL_MAX_NB_OF_RECIPIENTS_IN_SAME_EMAIL
850 if (!getDolGlobalString('MAIL_MAX_NB_OF_RECIPIENTS_TO_IN_SAME_EMAIL')) {
851 $conf->global->MAIL_MAX_NB_OF_RECIPIENTS_TO_IN_SAME_EMAIL = 10;
852 }
853 $tmparray1 = explode(',', $this->addr_to);
854 if (count($tmparray1) > $conf->global->MAIL_MAX_NB_OF_RECIPIENTS_TO_IN_SAME_EMAIL) {
855 $this->error = 'Too much recipients in to:';
856 dol_syslog("CMailFile::sendfile: mail end error=".$this->error, LOG_WARNING);
857 return false;
858 }
859 if (!getDolGlobalString('MAIL_MAX_NB_OF_RECIPIENTS_CC_IN_SAME_EMAIL')) {
860 $conf->global->MAIL_MAX_NB_OF_RECIPIENTS_CC_IN_SAME_EMAIL = 10;
861 }
862 $tmparray2 = explode(',', $this->addr_cc);
863 if (count($tmparray2) > $conf->global->MAIL_MAX_NB_OF_RECIPIENTS_CC_IN_SAME_EMAIL) {
864 $this->error = 'Too much recipients in cc:';
865 dol_syslog("CMailFile::sendfile: mail end error=".$this->error, LOG_WARNING);
866 return false;
867 }
868 if (!getDolGlobalString('MAIL_MAX_NB_OF_RECIPIENTS_BCC_IN_SAME_EMAIL')) {
869 $conf->global->MAIL_MAX_NB_OF_RECIPIENTS_BCC_IN_SAME_EMAIL = 10;
870 }
871 $tmparray3 = explode(',', $this->addr_bcc);
872 if (count($tmparray3) > $conf->global->MAIL_MAX_NB_OF_RECIPIENTS_BCC_IN_SAME_EMAIL) {
873 $this->error = 'Too much recipients in bcc:';
874 dol_syslog("CMailFile::sendfile: mail end error=".$this->error, LOG_WARNING);
875 return false;
876 }
877 if (!getDolGlobalString('MAIL_MAX_NB_OF_RECIPIENTS_IN_SAME_EMAIL')) {
878 $conf->global->MAIL_MAX_NB_OF_RECIPIENTS_IN_SAME_EMAIL = 10;
879 }
880 if ((count($tmparray1) + count($tmparray2) + count($tmparray3)) > $conf->global->MAIL_MAX_NB_OF_RECIPIENTS_IN_SAME_EMAIL) {
881 $this->error = 'Too much recipients in to:, cc:, bcc:';
882 dol_syslog("CMailFile::sendfile: mail end error=".$this->error, LOG_WARNING);
883 return false;
884 }
885
886 $keyforsmtpserver = 'MAIN_MAIL_SMTP_SERVER';
887 $keyforsmtpport = 'MAIN_MAIL_SMTP_PORT';
888 $keyforsmtpid = 'MAIN_MAIL_SMTPS_ID';
889 $keyforsmtppw = 'MAIN_MAIL_SMTPS_PW';
890 $keyforsmtpauthtype = 'MAIN_MAIL_SMTPS_AUTH_TYPE';
891 $keyforsmtpoauthservice = 'MAIN_MAIL_SMTPS_OAUTH_SERVICE';
892 $keyfortls = 'MAIN_MAIL_EMAIL_TLS';
893 $keyforstarttls = 'MAIN_MAIL_EMAIL_STARTTLS';
894 $keyforsslseflsigned = 'MAIN_MAIL_EMAIL_SMTP_ALLOW_SELF_SIGNED';
895 if (!empty($this->sendcontext)) {
896 $smtpContextKey = strtoupper($this->sendcontext);
897 $smtpContextSendMode = getDolGlobalString('MAIN_MAIL_SENDMODE_'.$smtpContextKey);
898 if (!empty($smtpContextSendMode) && $smtpContextSendMode != 'default') {
899 $keyforsmtpserver = 'MAIN_MAIL_SMTP_SERVER_'.$smtpContextKey;
900 $keyforsmtpport = 'MAIN_MAIL_SMTP_PORT_'.$smtpContextKey;
901 $keyforsmtpid = 'MAIN_MAIL_SMTPS_ID_'.$smtpContextKey;
902 $keyforsmtppw = 'MAIN_MAIL_SMTPS_PW_'.$smtpContextKey;
903 $keyforsmtpauthtype = 'MAIN_MAIL_SMTPS_AUTH_TYPE_'.$smtpContextKey;
904 $keyforsmtpoauthservice = 'MAIN_MAIL_SMTPS_OAUTH_SERVICE_'.$smtpContextKey;
905 $keyfortls = 'MAIN_MAIL_EMAIL_TLS_'.$smtpContextKey;
906 $keyforstarttls = 'MAIN_MAIL_EMAIL_STARTTLS_'.$smtpContextKey;
907 $keyforsslseflsigned = 'MAIN_MAIL_EMAIL_SMTP_ALLOW_SELF_SIGNED_'.$smtpContextKey;
908 }
909 }
910
911 // Action according to chose sending method
912 if ($this->sendmode == 'mail') {
913 // Use mail php function (default PHP method)
914 // ------------------------------------------
915 dol_syslog("CMailFile::sendfile addr_to=".$this->addr_to.", subject=".$this->subject, LOG_NOTICE);
916 //dol_syslog("CMailFile::sendfile header=\n".$this->headers, LOG_DEBUG);
917 //dol_syslog("CMailFile::sendfile message=\n".$message);
918
919 // If Windows, sendmail_from must be defined
920 if (isset($_SERVER["WINDIR"])) {
921 if (empty($this->addr_from)) {
922 $this->addr_from = 'robot@example.com';
923 }
924 @ini_set('sendmail_from', $this->getValidAddress($this->addr_from, 2));
925 }
926
927 // Force parameters
928 //dol_syslog("CMailFile::sendfile conf->global->".$keyforsmtpserver."=".getDolGlobalString($keyforsmtpserver)." cpnf->global->".$keyforsmtpport."=".$conf->global->$keyforsmtpport, LOG_DEBUG);
929 if (getDolGlobalString($keyforsmtpserver)) {
930 ini_set('SMTP', getDolGlobalString($keyforsmtpserver));
931 }
932 if (getDolGlobalString($keyforsmtpport)) {
933 ini_set('smtp_port', getDolGlobalString($keyforsmtpport));
934 }
935
936 $res = true;
937 if ($res && !$this->subject) {
938 $this->error = "Failed to send mail with php mail to HOST=".ini_get('SMTP').", PORT=".ini_get('smtp_port')."<br>Subject is empty";
939 dol_syslog("CMailFile::sendfile: mail end error=".$this->error, LOG_ERR);
940 $res = false;
941 }
942 $dest = $this->getValidAddress($this->addr_to, 2);
943 if ($res && !$dest) {
944 $this->error = "Failed to send mail with php mail to HOST=".ini_get('SMTP').", PORT=".ini_get('smtp_port')."<br>Recipient address '$dest' invalid";
945 dol_syslog("CMailFile::sendfile: mail end error=".$this->error, LOG_ERR);
946 $res = false;
947 }
948
949 if ($res) {
950 $additionnalparam = ''; // By default
951 if (getDolGlobalString('MAIN_MAIL_ALLOW_SENDMAIL_F')) {
952 // When using the phpmail function, the mail command may force the from to the user of the login, for example: linuxuser@myserver.mydomain.com
953 // You can try to set this option to have the command use the From. if it does not work, you can also try the MAIN_MAIL_SENDMAIL_FORCE_BA.
954 // So forcing using the option -f of sendmail is possible if constant MAIN_MAIL_ALLOW_SENDMAIL_F is defined.
955 // Having this variable defined may create problems with some sendmail (option -f refused)
956 // Having this variable not defined may create problems with some other sendmail (option -f required)
957 $additionnalparam .= ($additionnalparam ? ' ' : '').(getDolGlobalString('MAIN_MAIL_ERRORS_TO') ? '-f'.$this->getValidAddress($conf->global->MAIN_MAIL_ERRORS_TO, 2) : ($this->addr_from != '' ? '-f'.$this->getValidAddress($this->addr_from, 2) : ''));
958 }
959 if (getDolGlobalString('MAIN_MAIL_SENDMAIL_FORCE_BA')) { // To force usage of -ba option. This option tells sendmail to read From: or Sender: to setup sender
960 $additionnalparam .= ($additionnalparam ? ' ' : '').'-ba';
961 }
962
963 if (getDolGlobalString('MAIN_MAIL_SENDMAIL_FORCE_ADDPARAM')) {
964 $additionnalparam .= ($additionnalparam ? ' ' : '').'-U '.$additionnalparam; // Use -U to add additional params
965 }
966
967 $linuxlike = 1;
968 if (preg_match('/^win/i', PHP_OS)) {
969 $linuxlike = 0;
970 }
971 if (preg_match('/^mac/i', PHP_OS)) {
972 $linuxlike = 0;
973 }
974
975 dol_syslog("CMailFile::sendfile: mail start".($linuxlike ? '' : " HOST=".ini_get('SMTP').", PORT=".ini_get('smtp_port')).", additionnal_parameters=".$additionnalparam, LOG_DEBUG);
976
977 $this->message = stripslashes($this->message);
978
979 if (getDolGlobalString('MAIN_MAIL_DEBUG')) {
980 $this->dump_mail();
981 }
982
983 // Encode subject if required.
984 $subjecttouse = $this->subject;
985 if (!ascii_check($subjecttouse)) {
986 $subjecttouse = $this->encodetorfc2822($subjecttouse);
987 }
988
989 if (!empty($additionnalparam)) {
990 $res = mail($dest, $subjecttouse, $this->message, $this->headers, $additionnalparam);
991 } else {
992 $res = mail($dest, $subjecttouse, $this->message, $this->headers);
993 }
994
995 if (!$res) {
996 $langs->load("errors");
997 $this->error = "Failed to send mail with php mail";
998 if (!$linuxlike) {
999 $this->error .= " to HOST=".ini_get('SMTP').", PORT=".ini_get('smtp_port'); // This values are value used only for non linuxlike systems
1000 }
1001 $this->error .= ".<br>";
1002 $this->error .= $langs->trans("ErrorPhpMailDelivery");
1003 dol_syslog("CMailFile::sendfile: mail end error=".$this->error, LOG_ERR);
1004
1005 if (getDolGlobalString('MAIN_MAIL_DEBUG')) {
1006 $this->save_dump_mail_in_err('Mail with topic '.$this->subject);
1007 }
1008 } else {
1009 dol_syslog("CMailFile::sendfile: mail end success", LOG_DEBUG);
1010 }
1011 }
1012
1013 if (isset($_SERVER["WINDIR"])) {
1014 @ini_restore('sendmail_from');
1015 }
1016
1017 // Restore parameters
1018 if (getDolGlobalString($keyforsmtpserver)) {
1019 ini_restore('SMTP');
1020 }
1021 if (getDolGlobalString($keyforsmtpport)) {
1022 ini_restore('smtp_port');
1023 }
1024 } elseif ($this->sendmode == 'smtps') {
1025 if (!is_object($this->smtps)) {
1026 $this->error = "Failed to send mail with smtps lib<br>Constructor of object CMailFile was not initialized without errors.";
1027 dol_syslog("CMailFile::sendfile: mail end error=".$this->error, LOG_ERR);
1028 return false;
1029 }
1030
1031 // Use SMTPS library
1032 // ------------------------------------------
1033 $this->smtps->setTransportType(0); // Only this method is coded in SMTPs library
1034
1035 // Clean parameters
1036 if (empty($conf->global->$keyforsmtpserver)) {
1037 $conf->global->$keyforsmtpserver = ini_get('SMTP');
1038 }
1039 if (empty($conf->global->$keyforsmtpport)) {
1040 $conf->global->$keyforsmtpport = ini_get('smtp_port');
1041 }
1042
1043 // If we use SSL/TLS
1044 $server = getDolGlobalString($keyforsmtpserver);
1045 $secure = '';
1046 if (!empty($conf->global->$keyfortls) && function_exists('openssl_open')) {
1047 $secure = 'ssl';
1048 }
1049 if (!empty($conf->global->$keyforstarttls) && function_exists('openssl_open')) {
1050 $secure = 'tls';
1051 }
1052 $server = ($secure ? $secure.'://' : '').$server;
1053
1054 $port = getDolGlobalInt($keyforsmtpport);
1055
1056 $this->smtps->setHost($server);
1057 $this->smtps->setPort($port); // 25, 465...;
1058
1059 $loginid = '';
1060 $loginpass = '';
1061 if (!empty($conf->global->$keyforsmtpid)) {
1062 $loginid = getDolGlobalString($keyforsmtpid);
1063 $this->smtps->setID($loginid);
1064 }
1065 if (!empty($conf->global->$keyforsmtppw)) {
1066 $loginpass = getDolGlobalString($keyforsmtppw);
1067 $this->smtps->setPW($loginpass);
1068 }
1069
1070 if (getDolGlobalString($keyforsmtpauthtype) === "XOAUTH2") {
1071 require_once DOL_DOCUMENT_ROOT.'/core/lib/oauth.lib.php'; // define $supportedoauth2array
1072
1073 $supportedoauth2array = getSupportedOauth2Array();
1074
1075 $keyforsupportedoauth2array = getDolGlobalString($keyforsmtpoauthservice);
1076 if (preg_match('/^.*-/', $keyforsupportedoauth2array)) {
1077 $keyforprovider = preg_replace('/^.*-/', '', $keyforsupportedoauth2array);
1078 } else {
1079 $keyforprovider = '';
1080 }
1081 $keyforsupportedoauth2array = preg_replace('/-.*$/', '', $keyforsupportedoauth2array);
1082 $keyforsupportedoauth2array = 'OAUTH_'.$keyforsupportedoauth2array.'_NAME';
1083
1084 if (!empty($supportedoauth2array)) {
1085 $nameofservice = ucfirst(strtolower(empty($supportedoauth2array[$keyforsupportedoauth2array]['callbackfile']) ? 'Unknown' : $supportedoauth2array[$keyforsupportedoauth2array]['callbackfile']));
1086 $nameofservice .= ($keyforprovider ? '-'.$keyforprovider : '');
1087 $OAUTH_SERVICENAME = $nameofservice;
1088 } else {
1089 $OAUTH_SERVICENAME = 'Unknown';
1090 }
1091
1092 $keyforparamtenant = 'OAUTH_'.strtoupper(empty($supportedoauth2array[$keyforsupportedoauth2array]['callbackfile']) ? 'Unknown' : $supportedoauth2array[$keyforsupportedoauth2array]['callbackfile']).($keyforprovider ? '-'.$keyforprovider : '').'_TENANT';
1093
1094 require_once DOL_DOCUMENT_ROOT.'/includes/OAuth/bootstrap.php';
1095
1096 $storage = new DoliStorage($db, $conf, $keyforprovider, getDolGlobalString($keyforparamtenant));
1097 try {
1098 $tokenobj = $storage->retrieveAccessToken($OAUTH_SERVICENAME);
1099
1100 $expire = false;
1101 // Is token expired or will token expire in the next 30 seconds
1102 if (is_object($tokenobj)) {
1103 $expire = ($tokenobj->getEndOfLife() !== -9002 && $tokenobj->getEndOfLife() !== -9001 && time() > ($tokenobj->getEndOfLife() - 30));
1104 }
1105 // Token expired so we refresh it
1106 if (is_object($tokenobj) && $expire) {
1107 $credentials = new Credentials(
1108 getDolGlobalString('OAUTH_'.getDolGlobalString($keyforsmtpoauthservice).'_ID'),
1109 getDolGlobalString('OAUTH_'.getDolGlobalString($keyforsmtpoauthservice).'_SECRET'),
1110 getDolGlobalString('OAUTH_'.getDolGlobalString($keyforsmtpoauthservice).'_URLAUTHORIZE')
1111 );
1112 $serviceFactory = new \OAuth\ServiceFactory();
1113 $oauthname = explode('-', $OAUTH_SERVICENAME);
1114 // ex service is Google-Emails we need only the first part Google
1115 $apiService = $serviceFactory->createService($oauthname[0], $credentials, $storage, array());
1116 // We have to save the token because Google give it only once
1117 $refreshtoken = $tokenobj->getRefreshToken();
1118 $tokenobj = $apiService->refreshAccessToken($tokenobj);
1119 $tokenobj->setRefreshToken($refreshtoken);
1120 $storage->storeAccessToken($OAUTH_SERVICENAME, $tokenobj);
1121
1122 $tokenobj = $storage->retrieveAccessToken($OAUTH_SERVICENAME);
1123 }
1124
1125 if (is_object($tokenobj)) {
1126 $this->smtps->setToken($tokenobj->getAccessToken());
1127 } else {
1128 $this->error = "Token not found";
1129 }
1130 } catch (Exception $e) {
1131 // Return an error if token not found
1132 $this->error = $e->getMessage();
1133 dol_syslog("CMailFile::sendfile: mail end error=".$this->error, LOG_ERR);
1134 }
1135 }
1136
1137 $res = true;
1138 $from = $this->smtps->getFrom('org');
1139 if ($res && !$from) {
1140 $this->error = "Failed to send mail with smtps lib to HOST=".$server.", PORT=" . getDolGlobalString($keyforsmtpport)." - Sender address '$from' invalid";
1141 dol_syslog("CMailFile::sendfile: mail end error=".$this->error, LOG_ERR);
1142 $res = false;
1143 }
1144 $dest = $this->smtps->getTo();
1145 if ($res && !$dest) {
1146 $this->error = "Failed to send mail with smtps lib to HOST=".$server.", PORT=" . getDolGlobalString($keyforsmtpport)." - Recipient address '$dest' invalid";
1147 dol_syslog("CMailFile::sendfile: mail end error=".$this->error, LOG_ERR);
1148 $res = false;
1149 }
1150
1151 if ($res) {
1152 dol_syslog("CMailFile::sendfile: sendMsg, HOST=".$server.", PORT=" . getDolGlobalString($keyforsmtpport), LOG_NOTICE);
1153
1154 if (getDolGlobalString('MAIN_MAIL_DEBUG')) {
1155 $this->smtps->setDebug(true);
1156 }
1157
1158 $result = $this->smtps->sendMsg();
1159
1160 if (getDolGlobalString('MAIN_MAIL_DEBUG')) {
1161 $this->dump_mail();
1162 }
1163
1164 $smtperrorcode = 0;
1165 if (! $result) {
1166 $smtperrorcode = $this->smtps->lastretval; // SMTP error code
1167 dol_syslog("CMailFile::sendfile: mail SMTP error code ".$smtperrorcode, LOG_WARNING);
1168
1169 if ($smtperrorcode == '421') { // Try later
1170 // TODO Add a delay and try again
1171 /*
1172 dol_syslog("CMailFile::sendfile: Try later error, so we wait and we retry");
1173 sleep(2);
1174
1175 $result = $this->smtps->sendMsg();
1176
1177 if (!empty($conf->global->MAIN_MAIL_DEBUG)) {
1178 $this->dump_mail();
1179 }
1180 */
1181 }
1182 }
1183
1184 $result = $this->smtps->getErrors(); // applicative error code (not SMTP error code)
1185 if (empty($this->error) && empty($result)) {
1186 dol_syslog("CMailFile::sendfile: mail end success", LOG_DEBUG);
1187 $res = true;
1188 } else {
1189 if (empty($this->error)) {
1190 $this->error = $result;
1191 }
1192 dol_syslog("CMailFile::sendfile: mail end error with smtps lib to HOST=".$server.", PORT=" . getDolGlobalString($keyforsmtpport)." - ".$this->error, LOG_ERR);
1193 $res = false;
1194
1195 if (getDolGlobalString('MAIN_MAIL_DEBUG')) {
1196 $this->save_dump_mail_in_err('Mail smtp error '.$smtperrorcode.' with topic '.$this->subject);
1197 }
1198 }
1199 }
1200 } elseif ($this->sendmode == 'swiftmailer') {
1201 // Use Swift Mailer library
1202 // ------------------------------------------
1203 require_once DOL_DOCUMENT_ROOT.'/includes/swiftmailer/lib/swift_required.php';
1204
1205 // Clean parameters
1206 if (empty($conf->global->$keyforsmtpserver)) {
1207 $conf->global->$keyforsmtpserver = ini_get('SMTP');
1208 }
1209 if (empty($conf->global->$keyforsmtpport)) {
1210 $conf->global->$keyforsmtpport = ini_get('smtp_port');
1211 }
1212
1213 // If we use SSL/TLS
1214 $server = getDolGlobalString($keyforsmtpserver);
1215 $secure = '';
1216 if (!empty($conf->global->$keyfortls) && function_exists('openssl_open')) {
1217 $secure = 'ssl';
1218 }
1219 if (!empty($conf->global->$keyforstarttls) && function_exists('openssl_open')) {
1220 $secure = 'tls';
1221 }
1222
1223 $this->transport = new Swift_SmtpTransport($server, getDolGlobalString($keyforsmtpport), $secure);
1224
1225 if (!empty($conf->global->$keyforsmtpid)) {
1226 $this->transport->setUsername(getDolGlobalString($keyforsmtpid));
1227 }
1228 if (!empty($conf->global->$keyforsmtppw) && getDolGlobalString($keyforsmtpauthtype) != "XOAUTH2") {
1229 $this->transport->setPassword(getDolGlobalString($keyforsmtppw));
1230 }
1231 if (getDolGlobalString($keyforsmtpauthtype) === "XOAUTH2") {
1232 require_once DOL_DOCUMENT_ROOT.'/core/lib/oauth.lib.php';
1233
1234 $supportedoauth2array = getSupportedOauth2Array();
1235
1236 $keyforsupportedoauth2array = getDolGlobalString($keyforsmtpoauthservice);
1237 if (preg_match('/^.*-/', $keyforsupportedoauth2array)) {
1238 $keyforprovider = preg_replace('/^.*-/', '', $keyforsupportedoauth2array);
1239 } else {
1240 $keyforprovider = '';
1241 }
1242 $keyforsupportedoauth2array = preg_replace('/-.*$/', '', $keyforsupportedoauth2array);
1243 $keyforsupportedoauth2array = 'OAUTH_'.$keyforsupportedoauth2array.'_NAME';
1244
1245 if (!empty($supportedoauth2array)) {
1246 $nameofservice = ucfirst(strtolower(empty($supportedoauth2array[$keyforsupportedoauth2array]['callbackfile']) ? 'Unknown' : $supportedoauth2array[$keyforsupportedoauth2array]['callbackfile']));
1247 $nameofservice .= ($keyforprovider ? '-'.$keyforprovider : '');
1248 $OAUTH_SERVICENAME = $nameofservice;
1249 } else {
1250 $OAUTH_SERVICENAME = 'Unknown';
1251 }
1252
1253 $keyforparamtenant = 'OAUTH_'.strtoupper(empty($supportedoauth2array[$keyforsupportedoauth2array]['callbackfile']) ? 'Unknown' : $supportedoauth2array[$keyforsupportedoauth2array]['callbackfile']).($keyforprovider ? '-'.$keyforprovider : '').'_TENANT';
1254
1255 require_once DOL_DOCUMENT_ROOT.'/includes/OAuth/bootstrap.php';
1256
1257 $storage = new DoliStorage($db, $conf, $keyforprovider, getDolGlobalString($keyforparamtenant));
1258
1259 try {
1260 $tokenobj = $storage->retrieveAccessToken($OAUTH_SERVICENAME);
1261
1262 $expire = false;
1263 // Is token expired or will token expire in the next 30 seconds
1264 if (is_object($tokenobj)) {
1265 $expire = ($tokenobj->getEndOfLife() !== -9002 && $tokenobj->getEndOfLife() !== -9001 && time() > ($tokenobj->getEndOfLife() - 30));
1266 }
1267 // Token expired so we refresh it
1268 if (is_object($tokenobj) && $expire) {
1269 $credentials = new Credentials(
1270 getDolGlobalString('OAUTH_'.getDolGlobalString($keyforsmtpoauthservice).'_ID'),
1271 getDolGlobalString('OAUTH_'.getDolGlobalString($keyforsmtpoauthservice).'_SECRET'),
1272 getDolGlobalString('OAUTH_'.getDolGlobalString($keyforsmtpoauthservice).'_URLAUTHORIZE')
1273 );
1274 $serviceFactory = new \OAuth\ServiceFactory();
1275 $oauthname = explode('-', $OAUTH_SERVICENAME);
1276 // ex service is Google-Emails we need only the first part Google
1277 $apiService = $serviceFactory->createService($oauthname[0], $credentials, $storage, array());
1278 // We have to save the token because Google give it only once
1279 $refreshtoken = $tokenobj->getRefreshToken();
1280 $tokenobj = $apiService->refreshAccessToken($tokenobj);
1281 $tokenobj->setRefreshToken($refreshtoken);
1282 $storage->storeAccessToken($OAUTH_SERVICENAME, $tokenobj);
1283
1284 $tokenobj = $storage->retrieveAccessToken($OAUTH_SERVICENAME);
1285 }
1286
1287 if (is_object($tokenobj)) {
1288 $this->transport->setAuthMode('XOAUTH2');
1289 $this->transport->setPassword($tokenobj->getAccessToken());
1290 } else {
1291 $this->errors[] = "Token not found";
1292 }
1293 } catch (Exception $e) {
1294 // Return an error if token not found
1295 $this->errors[] = $e->getMessage();
1296 dol_syslog("CMailFile::sendfile: mail end error=".$e->getMessage(), LOG_ERR);
1297 }
1298 }
1299 if (getDolGlobalString($keyforsslseflsigned)) {
1300 $this->transport->setStreamOptions(array('ssl' => array('allow_self_signed' => true, 'verify_peer' => false)));
1301 }
1302 //$smtps->_msgReplyTo = 'reply@web.com';
1303
1304 // Switch content encoding to base64 - avoid the doubledot issue with quoted-printable
1305 $contentEncoderBase64 = new Swift_Mime_ContentEncoder_Base64ContentEncoder();
1306 $this->message->setEncoder($contentEncoderBase64);
1307
1308 // Create the Mailer using your created Transport
1309 $this->mailer = new Swift_Mailer($this->transport);
1310
1311 // DKIM SIGN
1312 if (getDolGlobalString('MAIN_MAIL_EMAIL_DKIM_ENABLED')) {
1313 $privateKey = getDolGlobalString('MAIN_MAIL_EMAIL_DKIM_PRIVATE_KEY');
1314 $domainName = getDolGlobalString('MAIN_MAIL_EMAIL_DKIM_DOMAIN');
1315 $selector = getDolGlobalString('MAIN_MAIL_EMAIL_DKIM_SELECTOR');
1316 $signer = new Swift_Signers_DKIMSigner($privateKey, $domainName, $selector);
1317 $this->message->attachSigner($signer->ignoreHeader('Return-Path'));
1318 }
1319
1320 if (getDolGlobalString('MAIN_MAIL_DEBUG')) {
1321 // To use the ArrayLogger
1322 $this->logger = new Swift_Plugins_Loggers_ArrayLogger();
1323 // Or to use the Echo Logger
1324 //$this->logger = new Swift_Plugins_Loggers_EchoLogger();
1325 $this->mailer->registerPlugin(new Swift_Plugins_LoggerPlugin($this->logger));
1326 }
1327
1328 dol_syslog("CMailFile::sendfile: mailer->send, HOST=".$server.", PORT=" . getDolGlobalString($keyforsmtpport), LOG_NOTICE);
1329
1330 // send mail
1331 $failedRecipients = array();
1332 try {
1333 $result = $this->mailer->send($this->message, $failedRecipients);
1334 } catch (Exception $e) {
1335 $this->errors[] = $e->getMessage();
1336 }
1337 if (getDolGlobalString('MAIN_MAIL_DEBUG')) {
1338 $this->dump_mail();
1339 }
1340
1341 $res = true;
1342 if (!empty($this->error) || !empty($this->errors) || !$result) {
1343 if (!empty($failedRecipients)) {
1344 $this->error = 'Transport failed for the following addresses: "' . implode('", "', $failedRecipients) . '".';
1345 $this->errors[] = $this->error;
1346 }
1347 dol_syslog("CMailFile::sendfile: mail end error=". implode(' ', $this->errors), LOG_ERR);
1348 $res = false;
1349
1350 if (getDolGlobalString('MAIN_MAIL_DEBUG')) {
1351 $this->save_dump_mail_in_err('Mail with topic '.$this->subject);
1352 }
1353 } else {
1354 dol_syslog("CMailFile::sendfile: mail end success", LOG_DEBUG);
1355 }
1356 } else {
1357 // Send mail method not correctly defined
1358 // --------------------------------------
1359
1360 $this->error = 'Bad value for sendmode';
1361 return false;
1362 }
1363
1364 // Now we delete image files that were created dynamically to manage data inline files
1365 foreach ($this->html_images as $val) {
1366 if (!empty($val['type']) && $val['type'] == 'cidfromdata') {
1367 //dol_delete($val['fullpath']);
1368 }
1369 }
1370
1371 $parameters = array('sent' => $res);
1372 $action = '';
1373 $reshook = $hookmanager->executeHooks('sendMailAfter', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1374 if ($reshook < 0) {
1375 $this->error = "Error in hook maildao sendMailAfter ".$reshook;
1376 dol_syslog("CMailFile::sendfile: mail end error=".$this->error, LOG_ERR);
1377
1378 return false;
1379 }
1380 } else {
1381 $this->error = 'No mail sent. Feature is disabled by option MAIN_DISABLE_ALL_MAILS';
1382 dol_syslog("CMailFile::sendfile: ".$this->error, LOG_WARNING);
1383 }
1384
1385 error_reporting($errorlevel); // Reactive niveau erreur origine
1386 return $res;
1387 }
1388
1395 public static function encodetorfc2822($stringtoencode)
1396 {
1397 global $conf;
1398 return '=?'.$conf->file->character_set_client.'?B?'.base64_encode($stringtoencode).'?=';
1399 }
1400
1401 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1408 private function _encode_file($sourcefile)
1409 {
1410 // phpcs:enable
1411 $newsourcefile = dol_osencode($sourcefile);
1412
1413 if (is_readable($newsourcefile)) {
1414 $contents = file_get_contents($newsourcefile); // Need PHP 4.3
1415 $encoded = chunk_split(base64_encode($contents), 76, $this->eol); // 76 max is defined into http://tools.ietf.org/html/rfc2047
1416 return $encoded;
1417 } else {
1418 $this->error = "Error in _encode_file() method: Can't read file '".$sourcefile."'";
1419 dol_syslog("CMailFile::_encode_file: ".$this->error, LOG_ERR);
1420 return -1;
1421 }
1422 }
1423
1424
1425 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1433 public function dump_mail()
1434 {
1435 // phpcs:enable
1436 global $dolibarr_main_data_root;
1437
1438 if (@is_writable($dolibarr_main_data_root)) { // Avoid fatal error on fopen with open_basedir
1439 $outputfile = $dolibarr_main_data_root."/dolibarr_mail.log";
1440 $fp = fopen($outputfile, "w"); // overwrite
1441
1442 if ($this->sendmode == 'mail') {
1443 fwrite($fp, $this->headers);
1444 fwrite($fp, $this->eol); // This eol is added by the mail function, so we add it in log
1445 fwrite($fp, $this->message);
1446 } elseif ($this->sendmode == 'smtps') {
1447 fwrite($fp, $this->smtps->log); // this->smtps->log is filled only if MAIN_MAIL_DEBUG was set to on
1448 } elseif ($this->sendmode == 'swiftmailer') {
1449 fwrite($fp, "smtpheader=\n".$this->message->getHeaders()->toString()."\n");
1450 fwrite($fp, $this->logger->dump()); // this->logger is filled only if MAIN_MAIL_DEBUG was set to on
1451 }
1452
1453 fclose($fp);
1454 dolChmod($outputfile);
1455
1456 // Move dolibarr_mail.log into a dolibarr_mail.YYYYMMDD.log
1457 if (getDolGlobalString('MAIN_MAIL_DEBUG_LOG_WITH_DATE')) {
1458 $destfile = $dolibarr_main_data_root."/dolibarr_mail.".dol_print_date(dol_now(), 'dayhourlog', 'gmt').".log";
1459
1460 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1461 dol_move($outputfile, $destfile, 0, 1, 0, 0);
1462 }
1463 }
1464 }
1465
1466 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1474 public function save_dump_mail_in_err($message = '')
1475 {
1476 global $dolibarr_main_data_root;
1477
1478 if (@is_writable($dolibarr_main_data_root)) { // Avoid fatal error on fopen with open_basedir
1479 $srcfile = $dolibarr_main_data_root."/dolibarr_mail.log";
1480
1481 // Add message to dolibarr_mail.log. We do not use dol_syslog() on purpose,
1482 // to be sure to write into dolibarr_mail.log
1483 if ($message) {
1484 // Test constant SYSLOG_FILE_NO_ERROR (should stay a constant defined with define('SYSLOG_FILE_NO_ERROR',1);
1485 if (defined('SYSLOG_FILE_NO_ERROR')) {
1486 $filefd = @fopen($srcfile, 'a+');
1487 } else {
1488 $filefd = fopen($srcfile, 'a+');
1489 }
1490 if ($filefd) {
1491 fwrite($filefd, $message."\n");
1492 fclose($filefd);
1493 dolChmod($srcfile);
1494 }
1495 }
1496
1497 // Move dolibarr_mail.log into a dolibarr_mail.err or dolibarr_mail.date.err
1498 if (getDolGlobalString('MAIN_MAIL_DEBUG_ERR_WITH_DATE')) {
1499 $destfile = $dolibarr_main_data_root."/dolibarr_mail.".dol_print_date(dol_now(), 'dayhourlog', 'gmt').".err";
1500 } else {
1501 $destfile = $dolibarr_main_data_root."/dolibarr_mail.err";
1502 }
1503
1504 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1505 dol_move($srcfile, $destfile, 0, 1, 0, 0);
1506 }
1507 }
1508
1509
1516 public function checkIfHTML($msg)
1517 {
1518 if (!preg_match('/^[\s\t]*<html/i', $msg)) {
1519 $out = "<html><head><title></title>";
1520 if (!empty($this->styleCSS)) {
1521 $out .= $this->styleCSS;
1522 }
1523 $out .= "</head><body";
1524 if (!empty($this->bodyCSS)) {
1525 $out .= $this->bodyCSS;
1526 }
1527 $out .= ">";
1528 $out .= $msg;
1529 $out .= "</body></html>";
1530 } else {
1531 $out = $msg;
1532 }
1533
1534 return $out;
1535 }
1536
1542 public function buildCSS()
1543 {
1544 if (!empty($this->css)) {
1545 // Style CSS
1546 $this->styleCSS = '<style type="text/css">';
1547 $this->styleCSS .= 'body {';
1548
1549 if ($this->css['bgcolor']) {
1550 $this->styleCSS .= ' background-color: '.$this->css['bgcolor'].';';
1551 $this->bodyCSS .= ' bgcolor="'.$this->css['bgcolor'].'"';
1552 }
1553 if ($this->css['bgimage']) {
1554 // TODO recuperer cid
1555 $this->styleCSS .= ' background-image: url("cid:'.$this->css['bgimage_cid'].'");';
1556 }
1557 $this->styleCSS .= '}';
1558 $this->styleCSS .= '</style>';
1559 }
1560 }
1561
1562
1563 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1569 public function write_smtpheaders()
1570 {
1571 // phpcs:enable
1572 $out = "";
1573 $host = dol_getprefix('email');
1574
1575 // Sender
1576 //$out.= "Sender: ".getValidAddress($this->addr_from,2)).$this->eol2;
1577 $out .= "From: ".$this->getValidAddress($this->addr_from, 3, 1).$this->eol2;
1578 if (getDolGlobalString('MAIN_MAIL_SENDMAIL_FORCE_BA')) {
1579 $out .= "To: ".$this->getValidAddress($this->addr_to, 0, 1).$this->eol2;
1580 }
1581 // Return-Path is important because it is used by SPF. Some MTA does not read Return-Path from header but from command line. See option MAIN_MAIL_ALLOW_SENDMAIL_F for that.
1582 $out .= "Return-Path: ".$this->getValidAddress($this->addr_from, 0, 1).$this->eol2;
1583 if (isset($this->reply_to) && $this->reply_to) {
1584 $out .= "Reply-To: ".$this->getValidAddress($this->reply_to, 2).$this->eol2;
1585 }
1586 if (isset($this->errors_to) && $this->errors_to) {
1587 $out .= "Errors-To: ".$this->getValidAddress($this->errors_to, 2).$this->eol2;
1588 }
1589
1590 // Receiver
1591 if (isset($this->addr_cc) && $this->addr_cc) {
1592 $out .= "Cc: ".$this->getValidAddress($this->addr_cc, 2).$this->eol2;
1593 }
1594 if (isset($this->addr_bcc) && $this->addr_bcc) {
1595 $out .= "Bcc: ".$this->getValidAddress($this->addr_bcc, 2).$this->eol2; // TODO Question: bcc must not be into header, only into SMTP command "RCPT TO". Does php mail support this ?
1596 }
1597
1598 // Delivery receipt
1599 if (isset($this->deliveryreceipt) && $this->deliveryreceipt == 1) {
1600 $out .= "Disposition-Notification-To: ".$this->getValidAddress($this->addr_from, 2).$this->eol2;
1601 }
1602
1603 //$out.= "X-Priority: 3".$this->eol2;
1604
1605 $out .= 'Date: '.date("r").$this->eol2;
1606
1607 $trackid = $this->trackid;
1608 if ($trackid) {
1609 $this->msgid = time().'.phpmail-dolibarr-'.$trackid.'@'.$host;
1610 $out .= 'Message-ID: <'.$this->msgid.">".$this->eol2; // Uppercase seems replaced by phpmail
1611 $out .= 'X-Dolibarr-TRACKID: '.$trackid.'@'.$host.$this->eol2;
1612 } else {
1613 $this->msgid = time().'.phpmail@'.$host;
1614 $out .= 'Message-ID: <'.$this->msgid.">".$this->eol2;
1615 }
1616
1617 // Add 'In-Reply-To:' header with the Message-Id we answer
1618 if (!empty($this->in_reply_to)) {
1619 $out .= 'In-Reply-To: <'.$this->in_reply_to.'>'.$this->eol2;
1620 }
1621 // Add 'References:' header with list of all Message-ID in thread history
1622 if (!empty($this->references)) {
1623 $out .= 'References: '.$this->references.$this->eol2;
1624 }
1625
1626 if (!empty($_SERVER['REMOTE_ADDR'])) {
1627 $out .= "X-RemoteAddr: ".$_SERVER['REMOTE_ADDR'].$this->eol2;
1628 }
1629 $out .= "X-Mailer: Dolibarr version ".DOL_VERSION." (using php mail)".$this->eol2;
1630 $out .= "Mime-Version: 1.0".$this->eol2;
1631
1632 //$out.= "From: ".$this->getValidAddress($this->addr_from,3,1).$this->eol;
1633
1634 $out .= "Content-Type: multipart/mixed;".$this->eol2." boundary=\"".$this->mixed_boundary."\"".$this->eol2;
1635 $out .= "Content-Transfer-Encoding: 8bit".$this->eol2; // TODO Seems to be ignored. Header is 7bit once received.
1636
1637 dol_syslog("CMailFile::write_smtpheaders smtp_header=\n".$out, LOG_DEBUG);
1638 return $out;
1639 }
1640
1641
1642 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1650 public function write_mimeheaders($filename_list, $mimefilename_list)
1651 {
1652 // phpcs:enable
1653 $mimedone = 0;
1654 $out = "";
1655
1656 if (is_array($filename_list)) {
1657 $filename_list_size = count($filename_list);
1658 for ($i = 0; $i < $filename_list_size; $i++) {
1659 if ($filename_list[$i]) {
1660 if ($mimefilename_list[$i]) {
1661 $filename_list[$i] = $mimefilename_list[$i];
1662 }
1663 $out .= "X-attachments: $filename_list[$i]".$this->eol2;
1664 }
1665 }
1666 }
1667
1668 dol_syslog("CMailFile::write_mimeheaders mime_header=\n".$out, LOG_DEBUG);
1669 return $out;
1670 }
1671
1672 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1679 public function write_body($msgtext)
1680 {
1681 // phpcs:enable
1682 global $conf;
1683
1684 $out = '';
1685
1686 $out .= "--".$this->mixed_boundary.$this->eol;
1687
1688 if ($this->atleastoneimage) {
1689 $out .= "Content-Type: multipart/alternative;".$this->eol." boundary=\"".$this->alternative_boundary."\"".$this->eol;
1690 $out .= $this->eol;
1691 $out .= "--".$this->alternative_boundary.$this->eol;
1692 }
1693
1694 // Make RFC821 Compliant, replace bare linefeeds
1695 $strContent = preg_replace("/(?<!\r)\n/si", "\r\n", $msgtext); // PCRE modifier /s means new lines are common chars
1696 if (getDolGlobalString('MAIN_FIX_FOR_BUGGED_MTA')) {
1697 $strContent = preg_replace("/\r\n/si", "\n", $strContent); // PCRE modifier /s means new lines are common chars
1698 }
1699
1700 $strContentAltText = '';
1701 if ($this->msgishtml) {
1702 // Similar code to forge a text from html is also in smtps.class.php
1703 $strContentAltText = preg_replace("/<br\s*[^>]*>/", " ", $strContent);
1704 // TODO We could replace <img ...> with [Filename.ext] like Gmail do.
1705 $strContentAltText = html_entity_decode(strip_tags($strContentAltText)); // Remove any HTML tags
1706 $strContentAltText = trim(wordwrap($strContentAltText, 75, !getDolGlobalString('MAIN_FIX_FOR_BUGGED_MTA') ? "\r\n" : "\n"));
1707
1708 // Check if html header already in message, if not complete the message
1709 $strContent = $this->checkIfHTML($strContent); // This add a header and a body including custom CSS to the HTML content
1710 }
1711
1712 // Make RFC2045 Compliant, split lines
1713 //$strContent = rtrim(chunk_split($strContent)); // Function chunck_split seems ko if not used on a base64 content
1714 // TODO Encode main content into base64 and use the chunk_split, or quoted-printable
1715 $strContent = rtrim(wordwrap($strContent, 75, !getDolGlobalString('MAIN_FIX_FOR_BUGGED_MTA') ? "\r\n" : "\n")); // TODO Using this method creates unexpected line break on text/plain content.
1716
1717 if ($this->msgishtml) {
1718 if ($this->atleastoneimage) {
1719 $out .= "Content-Type: text/plain; charset=".$conf->file->character_set_client.$this->eol;
1720 //$out.= "Content-Transfer-Encoding: 7bit".$this->eol;
1721 $out .= $this->eol.($strContentAltText ? $strContentAltText : strip_tags($strContent)).$this->eol; // Add plain text message
1722 $out .= "--".$this->alternative_boundary.$this->eol;
1723 $out .= "Content-Type: multipart/related;".$this->eol." boundary=\"".$this->related_boundary."\"".$this->eol;
1724 $out .= $this->eol;
1725 $out .= "--".$this->related_boundary.$this->eol;
1726 }
1727
1728 if (!$this->atleastoneimage && $strContentAltText && getDolGlobalString('MAIN_MAIL_USE_MULTI_PART')) { // Add plain text message part before html part
1729 $out .= "Content-Type: multipart/alternative;".$this->eol." boundary=\"".$this->alternative_boundary."\"".$this->eol;
1730 $out .= $this->eol;
1731 $out .= "--".$this->alternative_boundary.$this->eol;
1732 $out .= "Content-Type: text/plain; charset=".$conf->file->character_set_client.$this->eol;
1733 //$out.= "Content-Transfer-Encoding: 7bit".$this->eol;
1734 $out .= $this->eol.$strContentAltText.$this->eol;
1735 $out .= "--".$this->alternative_boundary.$this->eol;
1736 }
1737
1738 $out .= "Content-Type: text/html; charset=".$conf->file->character_set_client.$this->eol;
1739 //$out.= "Content-Transfer-Encoding: 7bit".$this->eol; // TODO Use base64
1740 $out .= $this->eol.$strContent.$this->eol;
1741
1742 if (!$this->atleastoneimage && $strContentAltText && getDolGlobalString('MAIN_MAIL_USE_MULTI_PART')) { // Add plain text message part after html part
1743 $out .= "--".$this->alternative_boundary."--".$this->eol;
1744 }
1745 } else {
1746 $out .= "Content-Type: text/plain; charset=".$conf->file->character_set_client.$this->eol;
1747 //$out.= "Content-Transfer-Encoding: 7bit".$this->eol;
1748 $out .= $this->eol.$strContent.$this->eol;
1749 }
1750
1751 $out .= $this->eol;
1752
1753 // Encode images
1754 if ($this->atleastoneimage) {
1755 $out .= $this->write_images($this->images_encoded);
1756 // always end related and end alternative after inline images
1757 $out .= "--".$this->related_boundary."--".$this->eol;
1758 $out .= $this->eol."--".$this->alternative_boundary."--".$this->eol;
1759 $out .= $this->eol;
1760 }
1761
1762 return $out;
1763 }
1764
1765 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1775 private function write_files($filename_list, $mimetype_list, $mimefilename_list, $cidlist)
1776 {
1777 // phpcs:enable
1778 $out = '';
1779
1780 $filename_list_size = count($filename_list);
1781 for ($i = 0; $i < $filename_list_size; $i++) {
1782 if ($filename_list[$i]) {
1783 dol_syslog("CMailFile::write_files: i=$i ".$filename_list[$i]);
1784 $encoded = $this->_encode_file($filename_list[$i]);
1785 if ($encoded !== -1) {
1786 if ($mimefilename_list[$i]) {
1787 $filename_list[$i] = $mimefilename_list[$i];
1788 }
1789 if (!$mimetype_list[$i]) {
1790 $mimetype_list[$i] = "application/octet-stream";
1791 }
1792
1793 // Skip files that have a CID (they will be added as inline images instead)
1794 if (!empty($cidlist) && is_array($cidlist) && isset($cidlist[$i]) && $cidlist[$i] !== null && $cidlist[$i] !== '') {
1795 continue; // Skip this file as it will be processed as inline image
1796 }
1797
1798 $out .= "--".$this->mixed_boundary.$this->eol;
1799
1800 $out .= "Content-Disposition: attachment; filename=\"".$filename_list[$i]."\"".$this->eol;
1801 $out .= "Content-Type: ".$mimetype_list[$i]."; name=\"".$filename_list[$i]."\"".$this->eol;
1802 $out .= "Content-Transfer-Encoding: base64".$this->eol;
1803 $out .= "Content-Description: ".$filename_list[$i].$this->eol;
1804 $out .= $this->eol;
1805 $out .= $encoded;
1806 $out .= $this->eol;
1807 //$out.= $this->eol;
1808 } else {
1809 return $encoded;
1810 }
1811 }
1812 }
1813
1814 return $out;
1815 }
1816
1817
1818 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1825 public function write_images($images_list)
1826 {
1827 // phpcs:enable
1828 $out = '';
1829
1830 if (is_array($images_list)) {
1831 foreach ($images_list as $img) {
1832 dol_syslog("CMailFile::write_images: ".$img["name"]);
1833
1834 $out .= "--".$this->related_boundary.$this->eol; // always related for an inline image
1835 $out .= "Content-Type: ".$img["content_type"]."; name=\"".$img["name"]."\"".$this->eol;
1836 $out .= "Content-Transfer-Encoding: base64".$this->eol;
1837 $out .= "Content-Disposition: inline; filename=\"".$img["name"]."\"".$this->eol;
1838 $out .= "Content-ID: <".$img["cid"].">".$this->eol;
1839 $out .= $this->eol;
1840 $out .= $img["image_encoded"];
1841 $out .= $this->eol;
1842 }
1843 }
1844
1845 return $out;
1846 }
1847
1848
1849 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1857 public function check_server_port($host, $port)
1858 {
1859 // phpcs:enable
1860 global $conf;
1861
1862 $_retVal = 0;
1863 $timeout = 5; // Timeout in seconds
1864
1865 if (function_exists('fsockopen')) {
1866 $keyforsmtpserver = 'MAIN_MAIL_SMTP_SERVER';
1867 $keyforsmtpport = 'MAIN_MAIL_SMTP_PORT';
1868 $keyforsmtpid = 'MAIN_MAIL_SMTPS_ID';
1869 $keyforsmtppw = 'MAIN_MAIL_SMTPS_PW';
1870 $keyforsmtpauthtype = 'MAIN_MAIL_SMTPS_AUTH_TYPE';
1871 $keyforsmtpoauthservice = 'MAIN_MAIL_SMTPS_OAUTH_SERVICE';
1872 $keyfortls = 'MAIN_MAIL_EMAIL_TLS';
1873 $keyforstarttls = 'MAIN_MAIL_EMAIL_STARTTLS';
1874 $keyforsslseflsigned = 'MAIN_MAIL_EMAIL_SMTP_ALLOW_SELF_SIGNED';
1875
1876 if (!empty($this->sendcontext)) {
1877 $smtpContextKey = strtoupper($this->sendcontext);
1878 $smtpContextSendMode = getDolGlobalString('MAIN_MAIL_SENDMODE_'.$smtpContextKey);
1879 if (!empty($smtpContextSendMode) && $smtpContextSendMode != 'default') {
1880 $keyforsmtpserver = 'MAIN_MAIL_SMTP_SERVER_'.$smtpContextKey;
1881 $keyforsmtpport = 'MAIN_MAIL_SMTP_PORT_'.$smtpContextKey;
1882 $keyforsmtpid = 'MAIN_MAIL_SMTPS_ID_'.$smtpContextKey;
1883 $keyforsmtppw = 'MAIN_MAIL_SMTPS_PW_'.$smtpContextKey;
1884 $keyforsmtpauthtype = 'MAIN_MAIL_SMTPS_AUTH_TYPE_'.$smtpContextKey;
1885 $keyforsmtpoauthservice = 'MAIN_MAIL_SMTPS_OAUTH_SERVICE_'.$smtpContextKey;
1886 $keyfortls = 'MAIN_MAIL_EMAIL_TLS_'.$smtpContextKey;
1887 $keyforstarttls = 'MAIN_MAIL_EMAIL_STARTTLS_'.$smtpContextKey;
1888 $keyforsslseflsigned = 'MAIN_MAIL_EMAIL_SMTP_ALLOW_SELF_SIGNED_'.$smtpContextKey;
1889 }
1890 }
1891
1892 // If we use SSL/TLS
1893 if (!empty($conf->global->$keyfortls) && function_exists('openssl_open')) {
1894 $host = 'ssl://'.$host;
1895 }
1896 // tls smtp start with no encryption
1897 //if (!empty($conf->global->MAIN_MAIL_EMAIL_STARTTLS) && function_exists('openssl_open')) $host='tls://'.$host;
1898
1899 dol_syslog("Try socket connection to host=".$host." port=".$port." timeout=".$timeout);
1900 //See if we can connect to the SMTP server
1901 $errno = 0;
1902 $errstr = '';
1903 if ($socket = @fsockopen(
1904 $host, // Host to test, IP or domain. Add ssl:// for SSL/TLS.
1905 $port, // which Port number to use
1906 $errno, // actual system level error
1907 $errstr, // and any text that goes with the error
1908 $timeout // timeout for reading/writing data over the socket
1909 )) {
1910 // Windows still does not have support for this timeout function
1911 if (function_exists('stream_set_timeout')) {
1912 stream_set_timeout($socket, $timeout, 0);
1913 }
1914
1915 dol_syslog("Now we wait for answer 220");
1916
1917 // Check response from Server
1918 if ($_retVal = $this->server_parse($socket, "220")) {
1919 $_retVal = $socket;
1920 }
1921 } else {
1922 $this->error = utf8_check('Error '.$errno.' - '.$errstr) ? 'Error '.$errno.' - '.$errstr : mb_convert_encoding('Error '.$errno.' - '.$errstr, 'UTF-8', 'ISO-8859-1');
1923 }
1924 }
1925 return $_retVal;
1926 }
1927
1928 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1937 public function server_parse($socket, $response)
1938 {
1939 // phpcs:enable
1940 $_retVal = true; // Indicates if Object was created or not
1941 $server_response = '';
1942
1943 while (substr($server_response, 3, 1) != ' ') {
1944 if (!($server_response = fgets($socket, 256))) {
1945 $this->error = "Couldn't get mail server response codes";
1946 return false;
1947 }
1948 }
1949
1950 if (!(substr($server_response, 0, 3) == $response)) {
1951 $this->error = "Ran into problems sending Mail.\r\nResponse: $server_response";
1952 $_retVal = false;
1953 }
1954
1955 return $_retVal;
1956 }
1957
1964 private function findHtmlImages($images_dir)
1965 {
1966 // Build the array of image extensions
1967 $extensions = array_keys($this->image_types);
1968
1969 // We search (into mail body this->html), if we find some strings like "... file=xxx.img"
1970 // For example when:
1971 // <img alt="" src="/viewimage.php?modulepart=medias&amp;entity=1&amp;file=image/picture.jpg" style="height:356px; width:1040px" />
1972 $matches = array();
1973 preg_match_all('/(?:"|\')([^"\']+\.('.implode('|', $extensions).'))(?:"|\')/Ui', $this->html, $matches); // If "xxx.ext" or 'xxx.ext' found
1974
1975 if (!empty($matches) && !empty($matches[1])) {
1976 $i = 0;
1977 // We are interested in $matches[1] only (the second set of parenthesis into regex)
1978 foreach ($matches[1] as $full) {
1979 $regs = array();
1980 if (preg_match('/file=([A-Za-z0-9_\-\/]+[\.]?[A-Za-z0-9]+)?$/i', $full, $regs)) { // If xxx is 'file=aaa'
1981 $img = $regs[1];
1982
1983 if (file_exists($images_dir.'/'.$img)) {
1984 // Image path in src
1985 $src = preg_quote($full, '/');
1986 // Image full path
1987 $this->html_images[$i]["fullpath"] = $images_dir.'/'.$img;
1988 // Image name
1989 $this->html_images[$i]["name"] = $img;
1990 // Content type
1991 $regext = array();
1992 if (preg_match('/^.+\.(\w{3,4})$/', $img, $regext)) {
1993 $ext = strtolower($regext[1]);
1994 $this->html_images[$i]["content_type"] = $this->image_types[$ext];
1995 }
1996 // cid
1997 $this->html_images[$i]["cid"] = dol_hash($this->html_images[$i]["fullpath"], 'md5'); // Force md5 hash (does not contain special chars)
1998 // type
1999 $this->html_images[$i]["type"] = 'cidfromurl';
2000
2001 $this->html = preg_replace("/src=\"$src\"|src='$src'/i", "src=\"cid:".$this->html_images[$i]["cid"]."\"", $this->html);
2002 }
2003 $i++;
2004 }
2005 }
2006
2007 if (!empty($this->html_images)) {
2008 $inline = array();
2009
2010 $i = 0;
2011
2012 foreach ($this->html_images as $img) {
2013 $fullpath = $images_dir.'/'.$img["name"];
2014
2015 // If duplicate images are embedded, they may show up as attachments, so remove them.
2016 if (!in_array($fullpath, $inline)) {
2017 // Read image file
2018 if ($image = file_get_contents($fullpath)) {
2019 // On garde que le nom de l'image
2020 $regs = array();
2021 preg_match('/([A-Za-z0-9_-]+[\.]?[A-Za-z0-9]+)?$/i', $img["name"], $regs);
2022 $imgName = $regs[1];
2023
2024 $this->images_encoded[$i]['name'] = $imgName;
2025 $this->images_encoded[$i]['fullpath'] = $fullpath;
2026 $this->images_encoded[$i]['content_type'] = $img["content_type"];
2027 $this->images_encoded[$i]['cid'] = $img["cid"];
2028 // Encodage de l'image
2029 $this->images_encoded[$i]["image_encoded"] = chunk_split(base64_encode($image), 68, $this->eol);
2030 $inline[] = $fullpath;
2031 }
2032 }
2033 $i++;
2034 }
2035 } else {
2036 return -1;
2037 }
2038
2039 return 1;
2040 } else {
2041 return 0;
2042 }
2043 }
2044
2052 private function findHtmlImagesIsSrcData($images_dir)
2053 {
2054 global $conf;
2055
2056 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
2057
2058 // Build the array of image extensions
2059 $extensions = array_keys($this->image_types);
2060
2061 if (empty($images_dir)) {
2062 //$images_dir = $conf->admin->dir_output.'/temp/'.uniqid('cmailfile');
2063 $images_dir = $conf->admin->dir_output.'/temp/cmailfile';
2064 }
2065
2066 if ($images_dir && !dol_is_dir($images_dir)) {
2067 dol_mkdir($images_dir, DOL_DATA_ROOT);
2068 }
2069
2070 // Uncomment this for debug
2071 /*
2072 global $dolibarr_main_data_root;
2073 $outputfile = $dolibarr_main_data_root."/dolibarr_mail.log";
2074 $fp = fopen($outputfile, "w+");
2075 fwrite($fp, $this->html);
2076 fclose($fp);
2077 */
2078
2079 // We search (into mail body this->html), if we find some strings like "... file=xxx.img"
2080 // For example when:
2081 // <img alt="" src="/src="data:image....;base64,...." />
2082 $matches = array();
2083 preg_match_all('/src="data:image\/('.implode('|', $extensions).');base64,([^"]+)"/Ui', $this->html, $matches); // If "xxx.ext" or 'xxx.ext' found
2084
2085 if (!empty($matches) && !empty($matches[1])) {
2086 if (empty($images_dir)) {
2087 // No temp directory provided, so we are not able to support conversion of data:image into physical images.
2088 $this->errors[] = 'NoTempDirProvidedInCMailConstructorSoCantConvertDataImgOnDisk';
2089 return -1;
2090 }
2091
2092 $i = count($this->html_images);
2093 foreach ($matches[1] as $key => $ext) {
2094 // We save the image to send in disk
2095 $filecontent = $matches[2][$key];
2096
2097 $cid = 'cid000'.dol_hash($filecontent, 'md5'); // The id must not change if image is same
2098
2099 $destfiletmp = $images_dir.'/'.$cid.'.'.$ext;
2100
2101 if (!dol_is_file($destfiletmp)) { // If file does not exist yet (this is the case for the first email sent with a data:image inside)
2102 dol_syslog("write the cid file ".$destfiletmp);
2103 $fhandle = @fopen($destfiletmp, 'w');
2104 if ($fhandle) {
2105 $nbofbyteswrote = fwrite($fhandle, base64_decode($filecontent));
2106 fclose($fhandle);
2107 dolChmod($destfiletmp);
2108 } else {
2109 $this->errors[] = "Failed to open file '".$destfiletmp."' for write";
2110 return -2;
2111 }
2112 }
2113
2114 if (file_exists($destfiletmp)) {
2115 // Image full path
2116 $this->html_images[$i]["fullpath"] = $destfiletmp;
2117 // Image name
2118 $this->html_images[$i]["name"] = basename($destfiletmp);
2119 // Content type
2120 $this->html_images[$i]["content_type"] = $this->image_types[strtolower($ext)];
2121 // cid
2122 $this->html_images[$i]["cid"] = $cid;
2123 // type
2124 $this->html_images[$i]["type"] = 'cidfromdata';
2125
2126 $this->html = str_replace('src="data:image/'.$ext.';base64,'.$filecontent.'"', 'src="cid:'.$this->html_images[$i]["cid"].'"', $this->html);
2127 }
2128 $i++;
2129 }
2130
2131 // Also add cidfromdata images to images_encoded array so they are sent as inline images
2132 foreach ($this->html_images as $img) {
2133 if ($img['type'] == 'cidfromdata') {
2134 $image_content = file_get_contents($img['fullpath']);
2135 if ($image_content !== false) {
2136 $idx = count($this->images_encoded);
2137 $this->images_encoded[$idx]['name'] = $img['name'];
2138 $this->images_encoded[$idx]['fullpath'] = $img['fullpath'];
2139 $this->images_encoded[$idx]['content_type'] = $img['content_type'];
2140 $this->images_encoded[$idx]['cid'] = $img['cid'];
2141 $this->images_encoded[$idx]['type'] = 'cidfromdata';
2142 $this->images_encoded[$idx]['image_encoded'] = chunk_split(base64_encode($image_content), 68, $this->eol);
2143 }
2144 }
2145 }
2146
2147 return 1;
2148 } else {
2149 return 0;
2150 }
2151 }
2152
2168 public static function getValidAddress($address, $format, $encode = 0, $maxnumberofemail = 0)
2169 {
2170 global $conf;
2171
2172 $ret = '';
2173
2174 $arrayaddress = (!empty($address) ? explode(',', $address) : array());
2175
2176 // Boucle sur chaque composant de l'address
2177 $i = 0;
2178 foreach ($arrayaddress as $val) {
2179 $regs = array();
2180 if (preg_match('/^(.*)<(.*)>$/i', trim($val), $regs)) {
2181 $name = trim($regs[1]);
2182 $email = trim($regs[2]);
2183 } else {
2184 $name = '';
2185 $email = trim($val);
2186 }
2187
2188 if ($email) {
2189 $i++;
2190
2191 $newemail = '';
2192 if ($format == 5) {
2193 $newemail = $name ? $name : $email;
2194 $newemail = '<a href="mailto:'.$email.'">'.$newemail.'</a>';
2195 }
2196 if ($format == 4) {
2197 $newemail = $name ? $name : $email;
2198 }
2199 if ($format == 2) {
2200 $newemail = $email;
2201 }
2202 if ($format == 1 || $format == 3) {
2203 $newemail = '<'.$email.'>';
2204 }
2205 if ($format == 0 || $format == 3) {
2206 if (getDolGlobalString('MAIN_MAIL_NO_FULL_EMAIL')) {
2207 $newemail = '<'.$email.'>';
2208 } elseif (!$name) {
2209 $newemail = '<'.$email.'>';
2210 } else {
2211 $newemail = ($format == 3 ? '"' : '').($encode ? self::encodetorfc2822($name) : $name).($format == 3 ? '"' : '').' <'.$email.'>';
2212 }
2213 }
2214
2215 $ret = ($ret ? $ret.',' : '').$newemail;
2216
2217 // Stop if we have too much records
2218 if ($maxnumberofemail && $i >= $maxnumberofemail) {
2219 if (count($arrayaddress) > $maxnumberofemail) {
2220 $ret .= '...';
2221 }
2222 break;
2223 }
2224 }
2225 }
2226
2227 return $ret;
2228 }
2229
2237 public static function getArrayAddress($address)
2238 {
2239 $ret = array();
2240
2241 $arrayaddress = explode(',', $address);
2242
2243 // Boucle sur chaque composant de l'address
2244 foreach ($arrayaddress as $val) {
2245 $regs = array();
2246 if (preg_match('/^(.*)<(.*)>$/i', trim($val), $regs)) {
2247 $name = trim($regs[1]);
2248 $email = trim($regs[2]);
2249 } else {
2250 $name = null;
2251 $email = trim($val);
2252 }
2253
2254 $ret[$email] = getDolGlobalString('MAIN_MAIL_NO_FULL_EMAIL') ? null : $name;
2255 }
2256
2257 return $ret;
2258 }
2259}
Class to send emails (with attachments or not) Usage: $mailfile = new CMailFile($subject,...
_encode_file($sourcefile)
Read a file on disk and return encoded content for emails (mode = 'mail')
write_body($msgtext)
Return email content (mode = 'mail')
__construct($subject, $to, $from, $msg, $filename_list=array(), $mimetype_list=array(), $mimefilename_list=array(), $addr_cc="", $addr_bcc="", $deliveryreceipt=0, $msgishtml=0, $errors_to='', $css='', $trackid='', $moreinheader='', $sendcontext='standard', $replyto='', $upload_dir_tmp='', $in_reply_to='', $references='')
CMailFile.
$bodyCSS
Defined background directly in body tag.
dump_mail()
Write content of a SMTP request into a dump file (mode = all) Used for debugging.
sendfile()
Send mail that was prepared by constructor.
save_dump_mail_in_err($message='')
Save content if mail is in error Used for debugging.
static encodetorfc2822($stringtoencode)
Encode subject according to RFC 2822 - http://en.wikipedia.org/wiki/MIME#Encoded-Word.
checkIfHTML($msg)
Correct an incomplete html string.
static getValidAddress($address, $format, $encode=0, $maxnumberofemail=0)
Return a formatted address string for SMTP protocol.
write_images($images_list)
Attach an image to email (mode = 'mail')
server_parse($socket, $response)
This function has been modified as provided by SirSir to allow multiline responses when using SMTP Ex...
write_smtpheaders()
Create SMTP headers (mode = 'mail')
findHtmlImagesIsSrcData($images_dir)
Seearch images with data:image format into html message.
$styleCSS
Defined css style for body background.
write_mimeheaders($filename_list, $mimefilename_list)
Create header MIME (mode = 'mail')
check_server_port($host, $port)
Try to create a socket connection.
buildCSS()
Build a css style (mode = all) into this->styleCSS and this->bodyCSS.
write_files($filename_list, $mimetype_list, $mimefilename_list, $cidlist)
Attach file to email (mode = 'mail')
static getArrayAddress($address)
Return a formatted array of address string for SMTP protocol.
findHtmlImages($images_dir)
Search images into html message and init array this->images_encoded if found.
Class to manage hooks.
Class to construct and send SMTP compliant email, even to a secure SMTP server, regardless of platfor...
dol_move($srcfile, $destfile, $newmask='0', $overwriteifexists=1, $testvirus=0, $indexdatabase=1, $moreinfo=array())
Move a file into another name.
dol_is_file($pathoffile)
Return if path is a file.
dol_is_dir($folder)
Test if filename is a directory.
dol_osencode($str)
Return a string encoded into OS filesystem encoding.
dol_nl2br($stringtoencode, $nl2brmode=0, $forxml=false)
Replace CRLF in string with a HTML BR tag.
dolChmod($filepath, $newmask='')
Change mod of a file.
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
dol_string_unaccent($str)
Clean a string from all accent characters to be used as ref, login or by dol_sanitizeFileName.
ascii_check($str)
Check if a string is in ASCII.
dol_textishtml($msg, $option=0)
Return if a text is a html content.
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
utf8_check($str)
Check if a string is in UTF8.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
dol_sanitizeEmail($stringtoclean)
Clean a string to use it as an Email.
getSupportedOauth2Array()
Return array of tabs to used on pages to setup cron module.
dol_hash($chain, $type='0', $nosalt=0)
Returns a hash (non reversible encryption) of a string.