dolibarr  9.0.0
CMailFile.class.php
Go to the documentation of this file.
1 <?php
37 class CMailFile
38 {
39  public $sendcontext;
40  public $sendmode;
41  public $sendsetup;
42 
43  var $subject; // Topic: Subject of email
44  var $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).
45  // Sender: Who send the email ("Sender" has sent emails on behalf of "From").
46  // Use it when the "From" is an email of a domain that is a SPF protected domain, and sending smtp server is not this domain. In such case, add Sender field with an email of the protected domain.
47  // Return-Path: Email where to send bounds.
48  var $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)
49  var $errors_to; // Errors-To: Email where to send errors.
50  var $addr_to;
51  var $addr_cc;
52  var $addr_bcc;
53  var $trackid;
54 
55  var $mixed_boundary;
56  var $related_boundary;
57  var $alternative_boundary;
58  var $deliveryreceipt;
59 
60  var $eol;
61  var $eol2;
62 
66  public $error='';
67 
68  var $smtps; // Contains SMTPs object (if this method is used)
69  var $phpmailer; // Contains PHPMailer object (if this method is used)
70 
74  public $css;
76  var $styleCSS;
78  var $bodyCSS;
79 
80  var $headers;
81  var $message;
82 
83  // Image
84  var $html;
85  var $image_boundary;
86  var $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).
87  var $html_images=array();
88  var $images_encoded=array();
89  var $image_types = array(
90  'gif' => 'image/gif',
91  'jpg' => 'image/jpeg',
92  'jpeg' => 'image/jpeg',
93  'jpe' => 'image/jpeg',
94  'bmp' => 'image/bmp',
95  'png' => 'image/png',
96  'tif' => 'image/tiff',
97  'tiff' => 'image/tiff',
98  );
99 
100 
122  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='')
123  {
124  global $conf, $dolibarr_main_data_root;
125 
126  $this->sendcontext = $sendcontext;
127 
128  if (empty($replyto)) $replyto=$from;
129 
130  // Define this->sendmode
131  $this->sendmode = '';
132  if ($this->sendcontext == 'emailing' && !empty($conf->global->MAIN_MAIL_SENDMODE_EMAILING) && $conf->global->MAIN_MAIL_SENDMODE_EMAILING != 'default')
133  {
134  $this->sendmode = $conf->global->MAIN_MAIL_SENDMODE_EMAILING;
135  }
136  if (empty($this->sendmode)) $this->sendmode=$conf->global->MAIN_MAIL_SENDMODE;
137  if (empty($this->sendmode)) $this->sendmode='mail';
138 
139  // We define end of line (RFC 821).
140  $this->eol="\r\n";
141  // We define end of line for header fields (RFC 822bis section 2.3 says header must contains \r\n).
142  $this->eol2="\r\n";
143  if (! empty($conf->global->MAIN_FIX_FOR_BUGGED_MTA))
144  {
145  $this->eol="\n";
146  $this->eol2="\n";
147  $moreinheader = str_replace("\r\n","\n",$moreinheader);
148  }
149 
150  // On defini mixed_boundary
151  $this->mixed_boundary = "multipart_x." . time() . ".x_boundary";
152 
153  // On defini related_boundary
154  $this->related_boundary = 'mul_'.dol_hash(uniqid("dolibarr2"), 3); // Force md5 hash (does not contains special chars)
155 
156  // On defini alternative_boundary
157  $this->alternative_boundary = 'mul_'.dol_hash(uniqid("dolibarr3"), 3); // Force md5 hash (does not contains special chars)
158 
159  dol_syslog("CMailFile::CMailfile: sendmode=".$this->sendmode." charset=".$conf->file->character_set_client." from=$from, to=$to, addr_cc=$addr_cc, addr_bcc=$addr_bcc, errors_to=$errors_to, trackid=$trackid sendcontext=$sendcontext", LOG_DEBUG);
160  dol_syslog("CMailFile::CMailfile: subject=".$subject.", deliveryreceipt=".$deliveryreceipt.", msgishtml=".$msgishtml, LOG_DEBUG);
161 
162  if (empty($subject))
163  {
164  dol_syslog("CMailFile::CMailfile: Try to send an email with empty subject");
165  $this->error='ErrorSubjectIsRequired';
166  return;
167  }
168  if (empty($msg))
169  {
170  dol_syslog("CMailFile::CMailfile: Try to send an email with empty body");
171  $msg='.'; // Avoid empty message (with empty message conten show a multipart structure)
172  }
173 
174  // Detect if message is HTML (use fast method)
175  if ($msgishtml == -1)
176  {
177  $this->msgishtml = 0;
178  if (dol_textishtml($msg)) $this->msgishtml = 1;
179  }
180  else
181  {
182  $this->msgishtml = $msgishtml;
183  }
184 
185  global $dolibarr_main_url_root;
186 
187  // Define $urlwithroot
188  $urlwithouturlroot=preg_replace('/'.preg_quote(DOL_URL_ROOT,'/').'$/i','',trim($dolibarr_main_url_root));
189  $urlwithroot=$urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file
190  //$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current
191 
192  // Replace relative /viewimage to absolute path
193  $msg = preg_replace('/src="'.preg_quote(DOL_URL_ROOT,'/').'\/viewimage\.php/ims', 'src="'.$urlwithroot.'/viewimage.php', $msg, -1, $nbrep);
194 
195  if (! empty($conf->global->MAIN_MAIL_FORCE_CONTENT_TYPE_TO_HTML)) $this->msgishtml=1; // To force to send everything with content type html.
196 
197  // Detect images
198  if ($this->msgishtml)
199  {
200  $this->html = $msg;
201 
202  if (! empty($conf->global->MAIN_MAIL_ADD_INLINE_IMAGES_IF_IN_MEDIAS))
203  {
204  $findimg = $this->findHtmlImages($dolibarr_main_data_root.'/medias');
205  }
206 
207  // Define if there is at least one file
208  if ($findimg)
209  {
210  foreach ($this->html_images as $i => $val)
211  {
212  if ($this->html_images[$i])
213  {
214  $this->atleastoneimage=1;
215  dol_syslog("CMailFile::CMailfile: html_images[$i]['name']=".$this->html_images[$i]['name'], LOG_DEBUG);
216  }
217  }
218  }
219  }
220 
221  // Define if there is at least one file
222  if (is_array($filename_list))
223  {
224  foreach ($filename_list as $i => $val)
225  {
226  if ($filename_list[$i])
227  {
228  $this->atleastonefile=1;
229  dol_syslog("CMailFile::CMailfile: filename_list[$i]=".$filename_list[$i].", mimetype_list[$i]=".$mimetype_list[$i]." mimefilename_list[$i]=".$mimefilename_list[$i], LOG_DEBUG);
230  }
231  }
232  }
233 
234  // Add autocopy to (Note: Adding bcc for specific modules are also done from pages)
235  if (! empty($conf->global->MAIN_MAIL_AUTOCOPY_TO)) $addr_bcc.=($addr_bcc?', ':'').$conf->global->MAIN_MAIL_AUTOCOPY_TO;
236 
237  // Action according to choosed sending method
238  if ($this->sendmode == 'mail')
239  {
240  // Use mail php function (default PHP method)
241  // ------------------------------------------
242 
243  $smtp_headers = "";
244  $mime_headers = "";
245  $text_body = "";
246  $files_encoded = "";
247 
248  // Define smtp_headers
249  $this->subject = $subject;
250  $this->addr_from = $from;
251  $this->reply_to = $replyto;
252  $this->errors_to = $errors_to;
253  $this->addr_to = $to;
254  $this->addr_cc = $addr_cc;
255  $this->addr_bcc = $addr_bcc;
256  $this->deliveryreceipt = $deliveryreceipt;
257  $this->trackid = $trackid;
258 
259  $smtp_headers = $this->write_smtpheaders();
260  if (! empty($moreinheader)) $smtp_headers.=$moreinheader; // $moreinheader contains the \r\n
261 
262  // Define mime_headers
263  $mime_headers = $this->write_mimeheaders($filename_list, $mimefilename_list);
264 
265  if (! empty($this->html))
266  {
267  if (!empty($css))
268  {
269  $this->css = $css;
270  $this->buildCSS(); // Build a css style (mode = all) into this->styleCSS and this->bodyCSS
271  }
272 
273  $msg = $this->html;
274  }
275 
276  // Define body in text_body
277  $text_body = $this->write_body($msg);
278 
279  // Add attachments to text_encoded
280  if ($this->atleastonefile)
281  {
282  $files_encoded = $this->write_files($filename_list,$mimetype_list,$mimefilename_list);
283  }
284 
285  // We now define $this->headers and $this->message
286  $this->headers = $smtp_headers . $mime_headers;
287  // On nettoie le header pour qu'il ne se termine pas par un retour chariot.
288  // Ceci evite aussi les lignes vides en fin qui peuvent etre interpretees
289  // comme des injections mail par les serveurs de messagerie.
290  $this->headers = preg_replace("/([\r\n]+)$/i","",$this->headers);
291 
292  //$this->message = $this->eol.'This is a message with multiple parts in MIME format.'.$this->eol;
293  $this->message = 'This is a message with multiple parts in MIME format.'.$this->eol;
294  $this->message.= $text_body . $files_encoded;
295  $this->message.= "--" . $this->mixed_boundary . "--" . $this->eol;
296  }
297  else if ($this->sendmode == 'smtps')
298  {
299  // Use SMTPS library
300  // ------------------------------------------
301 
302  require_once DOL_DOCUMENT_ROOT.'/core/class/smtps.class.php';
303  $smtps = new SMTPs();
304  $smtps->setCharSet($conf->file->character_set_client);
305 
306  $smtps->setSubject($this->encodetorfc2822($subject));
307  $smtps->setTO($this->getValidAddress($to,0,1));
308  $smtps->setFrom($this->getValidAddress($from,0,1));
309  $smtps->setTrackId($trackid);
310  $smtps->setReplyTo($this->getValidAddress($replyto,0,1));
311 
312  if (! empty($moreinheader)) $smtps->setMoreInHeader($moreinheader);
313 
314  if (! empty($this->html))
315  {
316  if (!empty($css))
317  {
318  $this->css = $css;
319  $this->buildCSS();
320  }
321  $msg = $this->html;
322  $msg = $this->checkIfHTML($msg);
323  }
324 
325  if ($this->msgishtml) $smtps->setBodyContent($msg,'html');
326  else $smtps->setBodyContent($msg,'plain');
327 
328  if ($this->atleastoneimage)
329  {
330  foreach ($this->images_encoded as $img)
331  {
332  $smtps->setImageInline($img['image_encoded'],$img['name'],$img['content_type'],$img['cid']);
333  }
334  }
335 
336  if ($this->atleastonefile)
337  {
338  foreach ($filename_list as $i => $val)
339  {
340  $content=file_get_contents($filename_list[$i]);
341  $smtps->setAttachment($content,$mimefilename_list[$i],$mimetype_list[$i]);
342  }
343  }
344 
345  $smtps->setCC($addr_cc);
346  $smtps->setBCC($addr_bcc);
347  $smtps->setErrorsTo($errors_to);
348  $smtps->setDeliveryReceipt($deliveryreceipt);
349 
350  $this->smtps=$smtps;
351  }
352  else if ($this->sendmode == 'swiftmailer')
353  {
354  // Use Swift Mailer library
355  // ------------------------------------------
356 
357  $host = dol_getprefix('email');
358 
359  require_once DOL_DOCUMENT_ROOT.'/includes/swiftmailer/lexer/lib/Doctrine/Common/Lexer/AbstractLexer.php';
360 
361  require_once DOL_DOCUMENT_ROOT.'/includes/swiftmailer/egulias/email-validator/EmailValidator/Exception/InvalidEmail.php';
362  require_once DOL_DOCUMENT_ROOT.'/includes/swiftmailer/egulias/email-validator/EmailValidator/Exception/NoDomainPart.php';
363  require_once DOL_DOCUMENT_ROOT.'/includes/swiftmailer/egulias/email-validator/EmailValidator/EmailParser.php';
364  require_once DOL_DOCUMENT_ROOT.'/includes/swiftmailer/egulias/email-validator/EmailValidator/EmailLexer.php';
365  require_once DOL_DOCUMENT_ROOT.'/includes/swiftmailer/egulias/email-validator/EmailValidator/EmailValidator.php';
366  require_once DOL_DOCUMENT_ROOT.'/includes/swiftmailer/egulias/email-validator/EmailValidator/Warning/Warning.php';
367  require_once DOL_DOCUMENT_ROOT.'/includes/swiftmailer/egulias/email-validator/EmailValidator/Warning/LocalTooLong.php';
368  require_once DOL_DOCUMENT_ROOT.'/includes/swiftmailer/egulias/email-validator/EmailValidator/Parser/Parser.php';
369  require_once DOL_DOCUMENT_ROOT.'/includes/swiftmailer/egulias/email-validator/EmailValidator/Parser/DomainPart.php';
370  require_once DOL_DOCUMENT_ROOT.'/includes/swiftmailer/egulias/email-validator/EmailValidator/Parser/LocalPart.php';
371  require_once DOL_DOCUMENT_ROOT.'/includes/swiftmailer/egulias/email-validator/EmailValidator/Validation/EmailValidation.php';
372  require_once DOL_DOCUMENT_ROOT.'/includes/swiftmailer/egulias/email-validator/EmailValidator/Validation/RFCValidation.php';
373 
374  require_once DOL_DOCUMENT_ROOT.'/includes/swiftmailer/lib/classes/Swift/InputByteStream.php';
375  require_once DOL_DOCUMENT_ROOT.'/includes/swiftmailer/lib/classes/Swift/Signer.php';
376  require_once DOL_DOCUMENT_ROOT.'/includes/swiftmailer/lib/classes/Swift/Signers/HeaderSigner.php';
377  require_once DOL_DOCUMENT_ROOT.'/includes/swiftmailer/lib/classes/Swift/Signers/DKIMSigner.php';
378  //require_once DOL_DOCUMENT_ROOT.'/includes/swiftmailer/lib/classes/Swift/SignedMessage.php';
379  require_once DOL_DOCUMENT_ROOT.'/includes/swiftmailer/lib/swift_required.php';
380  // Create the message
381  //$this->message = Swift_Message::newInstance();
382  $this->message = new Swift_Message();
383  //$this->message = new Swift_SignedMessage();
384  // Adding a trackid header to a message
385  $headers = $this->message->getHeaders();
386  $headers->addTextHeader('X-Dolibarr-TRACKID', $trackid . '@' . $host);
387  $headerID = time() . '.swiftmailer-dolibarr-' . $trackid . '@' . $host;
388  $msgid = $headers->get('Message-ID');
389  $msgid->setId($headerID);
390  $headers->addIdHeader('References', $headerID);
391  // TODO if (! empty($moreinheader)) ...
392 
393  // Give the message a subject
394  try {
395  $result = $this->message->setSubject($subject);
396  } catch (Exception $e) {
397  $this->errors[] = $e->getMessage();
398  }
399 
400  // Set the From address with an associative array
401  //$this->message->setFrom(array('john@doe.com' => 'John Doe'));
402  if (! empty($from)) {
403  try {
404  $result = $this->message->setFrom($this->getArrayAddress($from));
405  } catch (Exception $e) {
406  $this->errors[] = $e->getMessage();
407  }
408  }
409 
410  // Set the To addresses with an associative array
411  if (! empty($to)) {
412  try {
413  $result = $this->message->setTo($this->getArrayAddress($to));
414  } catch (Exception $e) {
415  $this->errors[] = $e->getMessage();
416  }
417  }
418 
419  if (! empty($replyto)) {
420  try {
421  $result = $this->message->SetReplyTo($this->getArrayAddress($replyto));
422  } catch (Exception $e) {
423  $this->errors[] = $e->getMessage();
424  }
425  }
426 
427  try {
428  $result = $this->message->setCharSet($conf->file->character_set_client);
429  } catch (Exception $e) {
430  $this->errors[] = $e->getMessage();
431  }
432 
433  if (! empty($this->html))
434  {
435  if (!empty($css))
436  {
437  $this->css = $css;
438  $this->buildCSS();
439  }
440  $msg = $this->html;
441  $msg = $this->checkIfHTML($msg);
442  }
443 
444  if ($this->atleastoneimage)
445  {
446  foreach ($this->images_encoded as $img)
447  {
448  //$img['fullpath'],$img['image_encoded'],$img['name'],$img['content_type'],$img['cid']
449  $attachment = Swift_Image::fromPath($img['fullpath'], $img['content_type']);
450  // embed image
451  $imgcid = $this->message->embed($attachment);
452  // replace cid by the one created by swiftmail in html message
453  $msg = str_replace("cid:".$img['cid'], $imgcid, $msg);
454  }
455  }
456 
457  if ($this->msgishtml) {
458  $this->message->setBody($msg,'text/html');
459  // And optionally an alternative body
460  $this->message->addPart(html_entity_decode(strip_tags($msg)), 'text/plain');
461  } else {
462  $this->message->setBody($msg,'text/plain');
463  // And optionally an alternative body
464  $this->message->addPart($msg, 'text/html');
465  }
466 
467  if ($this->atleastonefile)
468  {
469  foreach ($filename_list as $i => $val)
470  {
471  //$this->message->attach(Swift_Attachment::fromPath($filename_list[$i],$mimetype_list[$i]));
472  $attachment = Swift_Attachment::fromPath($filename_list[$i],$mimetype_list[$i]);
473  $this->message->attach($attachment);
474  }
475  }
476 
477  if (! empty($addr_cc)) $this->message->setCc($this->getArrayAddress($addr_cc));
478  if (! empty($addr_bcc)) $this->message->setBcc($this->getArrayAddress($addr_bcc));
479  //if (! empty($errors_to)) $this->message->setErrorsTo($this->getArrayAddress($errors_to);
480  if (isset($deliveryreceipt) && $deliveryreceipt == 1) $this->message->setReadReceiptTo($this->getArrayAddress($from));
481  }
482  else
483  {
484  // Send mail method not correctly defined
485  // --------------------------------------
486  $this->error = 'Bad value for sendmode';
487  }
488  }
489 
490 
496  function sendfile()
497  {
498  global $conf,$db,$langs;
499 
500  $errorlevel=error_reporting();
501  //error_reporting($errorlevel ^ E_WARNING); // Desactive warnings
502 
503  $res=false;
504 
505  if (empty($conf->global->MAIN_DISABLE_ALL_MAILS) || !empty($conf->global->MAIN_MAIL_FORCE_SENDTO))
506  {
507  require_once DOL_DOCUMENT_ROOT . '/core/class/hookmanager.class.php';
508  $hookmanager = new HookManager($db);
509  $hookmanager->initHooks(array('mail'));
510 
511  $parameters=array(); $action='';
512  $reshook = $hookmanager->executeHooks('sendMail', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
513  if ($reshook < 0)
514  {
515  $this->error = "Error in hook maildao sendMail " . $reshook;
516  dol_syslog("CMailFile::sendfile: mail end error=" . $this->error, LOG_ERR);
517 
518  return $reshook;
519  }
520  if ($reshook == 1) // Hook replace standard code
521  {
522  return true;
523  }
524 
525  // Check number of recipient is lower or equal than MAIL_MAX_NB_OF_RECIPIENTS_IN_SAME_EMAIL
526  if (empty($conf->global->MAIL_MAX_NB_OF_RECIPIENTS_TO_IN_SAME_EMAIL)) $conf->global->MAIL_MAX_NB_OF_RECIPIENTS_TO_IN_SAME_EMAIL=10;
527  $tmparray1 = explode(',', $this->addr_to);
528  if (count($tmparray1) > $conf->global->MAIL_MAX_NB_OF_RECIPIENTS_TO_IN_SAME_EMAIL)
529  {
530  $this->error = 'Too much recipients in to:';
531  dol_syslog("CMailFile::sendfile: mail end error=" . $this->error, LOG_WARNING);
532  return false;
533  }
534  if (empty($conf->global->MAIL_MAX_NB_OF_RECIPIENTS_CC_IN_SAME_EMAIL)) $conf->global->MAIL_MAX_NB_OF_RECIPIENTS_CC_IN_SAME_EMAIL=10;
535  $tmparray2 = explode(',', $this->addr_cc);
536  if (count($tmparray2) > $conf->global->MAIL_MAX_NB_OF_RECIPIENTS_CC_IN_SAME_EMAIL)
537  {
538  $this->error = 'Too much recipients in cc:';
539  dol_syslog("CMailFile::sendfile: mail end error=" . $this->error, LOG_WARNING);
540  return false;
541  }
542  if (empty($conf->global->MAIL_MAX_NB_OF_RECIPIENTS_BCC_IN_SAME_EMAIL)) $conf->global->MAIL_MAX_NB_OF_RECIPIENTS_BCC_IN_SAME_EMAIL=10;
543  $tmparray3 = explode(',', $this->addr_bcc);
544  if (count($tmparray3) > $conf->global->MAIL_MAX_NB_OF_RECIPIENTS_BCC_IN_SAME_EMAIL)
545  {
546  $this->error = 'Too much recipients in bcc:';
547  dol_syslog("CMailFile::sendfile: mail end error=" . $this->error, LOG_WARNING);
548  return false;
549  }
550  if (empty($conf->global->MAIL_MAX_NB_OF_RECIPIENTS_IN_SAME_EMAIL)) $conf->global->MAIL_MAX_NB_OF_RECIPIENTS_IN_SAME_EMAIL=10;
551  if ((count($tmparray1)+count($tmparray2)+count($tmparray3)) > $conf->global->MAIL_MAX_NB_OF_RECIPIENTS_IN_SAME_EMAIL)
552  {
553  $this->error = 'Too much recipients in to:, cc:, bcc:';
554  dol_syslog("CMailFile::sendfile: mail end error=" . $this->error, LOG_WARNING);
555  return false;
556  }
557 
558  $keyforsmtpserver='MAIN_MAIL_SMTP_SERVER';
559  $keyforsmtpport ='MAIN_MAIL_SMTP_PORT';
560  $keyforsmtpid ='MAIN_MAIL_SMTPS_ID';
561  $keyforsmtppw ='MAIN_MAIL_SMTPS_PW';
562  $keyfortls ='MAIN_MAIL_EMAIL_TLS';
563  $keyforstarttls ='MAIN_MAIL_EMAIL_STARTTLS';
564  if ($this->sendcontext == 'emailing' && !empty($conf->global->MAIN_MAIL_SENDMODE_EMAILING) && $conf->global->MAIN_MAIL_SENDMODE_EMAILING != 'default')
565  {
566  $keyforsmtpserver='MAIN_MAIL_SMTP_SERVER_EMAILING';
567  $keyforsmtpport ='MAIN_MAIL_SMTP_PORT_EMAILING';
568  $keyforsmtpid ='MAIN_MAIL_SMTPS_ID_EMAILING';
569  $keyforsmtppw ='MAIN_MAIL_SMTPS_PW_EMAILING';
570  $keyfortls ='MAIN_MAIL_EMAIL_TLS_EMAILING';
571  $keyforstarttls ='MAIN_MAIL_EMAIL_STARTTLS_EMAILING';
572  }
573 
574  if (!empty($conf->global->MAIN_MAIL_FORCE_SENDTO))
575  {
576  $this->addr_to = $conf->global->MAIN_MAIL_FORCE_SENDTO;
577  $this->addr_cc = '';
578  $this->addr_bcc = '';
579  }
580 
581  // Action according to choosed sending method
582  if ($this->sendmode == 'mail')
583  {
584  // Use mail php function (default PHP method)
585  // ------------------------------------------
586  dol_syslog("CMailFile::sendfile addr_to=".$this->addr_to.", subject=".$this->subject, LOG_DEBUG);
587  dol_syslog("CMailFile::sendfile header=\n".$this->headers, LOG_DEBUG);
588  //dol_syslog("CMailFile::sendfile message=\n".$message);
589 
590  // If Windows, sendmail_from must be defined
591  if (isset($_SERVER["WINDIR"]))
592  {
593  if (empty($this->addr_from)) $this->addr_from = 'robot@example.com';
594  @ini_set('sendmail_from',$this->getValidAddress($this->addr_from,2));
595  }
596 
597  // Force parameters
598  if (! empty($conf->global->$keyforsmtpserver)) ini_set('SMTP',$conf->global->$keyforsmtpserver);
599  if (! empty($conf->global->$keyforsmtpport)) ini_set('smtp_port',$conf->global->$keyforsmtpport);
600 
601  $res=true;
602  if ($res && ! $this->subject)
603  {
604  $this->error="Failed to send mail with php mail to HOST=".ini_get('SMTP').", PORT=".ini_get('smtp_port')."<br>Subject is empty";
605  dol_syslog("CMailFile::sendfile: mail end error=".$this->error, LOG_ERR);
606  $res=false;
607  }
608  $dest=$this->getValidAddress($this->addr_to,2);
609  if ($res && ! $dest)
610  {
611  $this->error="Failed to send mail with php mail to HOST=".ini_get('SMTP').", PORT=".ini_get('smtp_port')."<br>Recipient address '$dest' invalid";
612  dol_syslog("CMailFile::sendfile: mail end error=".$this->error, LOG_ERR);
613  $res=false;
614  }
615 
616  if ($res)
617  {
618  $additionnalparam = ''; // By default
619  if (! empty($conf->global->MAIN_MAIL_ALLOW_SENDMAIL_F))
620  {
621  // le "Return-Path" (retour des messages bounced) dans les header ne fonctionne pas avec tous les MTA
622  // Le forcage de la valeur grace à l'option -f de sendmail est donc possible si la constante MAIN_MAIL_ALLOW_SENDMAIL_F est definie.
623  // Having this variable defined may create problems with some sendmail (option -f refused)
624  // Having this variable not defined may create problems with some other sendmail (option -f required)
625  $additionnalparam .= ($additionnalparam?' ':'').(! empty($conf->global->MAIN_MAIL_ERRORS_TO) ? '-f' . $this->getValidAddress($conf->global->MAIN_MAIL_ERRORS_TO,2) : ($this->addr_from != '' ? '-f' . $this->getValidAddress($this->addr_from,2) : '') );
626  }
627  if (! empty($conf->global->MAIN_MAIL_SENDMAIL_FORCE_BA)) // To force usage of -ba option. This option tells sendmail to read From: or Sender: to setup sender
628  {
629  $additionnalparam .= ($additionnalparam?' ':'').'-ba';
630  }
631 
632  if (! empty($conf->global->MAIN_MAIL_SENDMAIL_FORCE_ADDPARAM)) $additionnalparam .= ($additionnalparam?' ':'').'-U '.$additionnalparam; // Use -U to add additionnal params
633 
634  dol_syslog("CMailFile::sendfile: mail start HOST=".ini_get('SMTP').", PORT=".ini_get('smtp_port').", additionnal_parameters=".$additionnalparam, LOG_DEBUG);
635 
636  $this->message=stripslashes($this->message);
637 
638  if (! empty($conf->global->MAIN_MAIL_DEBUG)) $this->dump_mail();
639 
640  if (! empty($additionnalparam)) $res = mail($dest, $this->encodetorfc2822($this->subject), $this->message, $this->headers, $additionnalparam);
641  else $res = mail($dest, $this->encodetorfc2822($this->subject), $this->message, $this->headers);
642 
643  if (! $res)
644  {
645  $langs->load("errors");
646  $this->error="Failed to send mail with php mail";
647  $linuxlike=1;
648  if (preg_match('/^win/i',PHP_OS)) $linuxlike=0;
649  if (preg_match('/^mac/i',PHP_OS)) $linuxlike=0;
650  if (! $linuxlike)
651  {
652  $this->error.=" to HOST=".ini_get('SMTP').", PORT=".ini_get('smtp_port'); // This values are value used only for non linuxlike systems
653  }
654  $this->error.=".<br>";
655  $this->error.=$langs->trans("ErrorPhpMailDelivery");
656  dol_syslog("CMailFile::sendfile: mail end error=".$this->error, LOG_ERR);
657  }
658  else
659  {
660  dol_syslog("CMailFile::sendfile: mail end success", LOG_DEBUG);
661  }
662  }
663 
664  if (isset($_SERVER["WINDIR"]))
665  {
666  @ini_restore('sendmail_from');
667  }
668 
669  // Restore parameters
670  if (! empty($conf->global->$keyforsmtpserver)) ini_restore('SMTP');
671  if (! empty($conf->global->$keyforsmtpport)) ini_restore('smtp_port');
672  }
673  else if ($this->sendmode == 'smtps')
674  {
675  if (! is_object($this->smtps))
676  {
677  $this->error="Failed to send mail with smtps lib to HOST=".$server.", PORT=".$conf->global->$keyforsmtpport."<br>Constructor of object CMailFile was not initialized without errors.";
678  dol_syslog("CMailFile::sendfile: mail end error=".$this->error, LOG_ERR);
679  return false;
680  }
681 
682  // Use SMTPS library
683  // ------------------------------------------
684  $this->smtps->setTransportType(0); // Only this method is coded in SMTPs library
685 
686  // Clean parameters
687  if (empty($conf->global->$keyforsmtpserver)) $conf->global->$keyforsmtpserver=ini_get('SMTP');
688  if (empty($conf->global->$keyforsmtpport)) $conf->global->$keyforsmtpport=ini_get('smtp_port');
689 
690  // If we use SSL/TLS
691  $server=$conf->global->$keyforsmtpserver;
692  $secure='';
693  if (! empty($conf->global->$keyfortls) && function_exists('openssl_open')) $secure='ssl';
694  if (! empty($conf->global->$keyforstarttls) && function_exists('openssl_open')) $secure='tls';
695  $server=($secure?$secure.'://':'').$server;
696 
697  $port=$conf->global->$keyforsmtpport;
698 
699  $this->smtps->setHost($server);
700  $this->smtps->setPort($port); // 25, 465...;
701 
702  $loginid=''; $loginpass='';
703  if (! empty($conf->global->$keyforsmtpid))
704  {
705  $loginid = $conf->global->$keyforsmtpid;
706  $this->smtps->setID($loginid);
707  }
708  if (! empty($conf->global->$keyforsmtppw))
709  {
710  $loginpass = $conf->global->$keyforsmtppw;
711  $this->smtps->setPW($loginpass);
712  }
713 
714  $res=true;
715  $from=$this->smtps->getFrom('org');
716  if ($res && ! $from)
717  {
718  $this->error="Failed to send mail with smtps lib to HOST=".$server.", PORT=".$conf->global->$keyforsmtpport."<br>Sender address '$from' invalid";
719  dol_syslog("CMailFile::sendfile: mail end error=".$this->error, LOG_ERR);
720  $res=false;
721  }
722  $dest=$this->smtps->getTo();
723  if ($res && ! $dest)
724  {
725  $this->error="Failed to send mail with smtps lib to HOST=".$server.", PORT=".$conf->global->$keyforsmtpport."<br>Recipient address '$dest' invalid";
726  dol_syslog("CMailFile::sendfile: mail end error=".$this->error, LOG_ERR);
727  $res=false;
728  }
729 
730  if ($res)
731  {
732  if (! empty($conf->global->MAIN_MAIL_DEBUG)) $this->smtps->setDebug(true);
733 
734  $result=$this->smtps->sendMsg();
735  //print $result;
736 
737  if (! empty($conf->global->MAIN_MAIL_DEBUG)) $this->dump_mail();
738 
739  $result=$this->smtps->getErrors();
740  if (empty($this->error) && empty($result))
741  {
742  dol_syslog("CMailFile::sendfile: mail end success", LOG_DEBUG);
743  $res=true;
744  }
745  else
746  {
747  if (empty($this->error)) $this->error=$result;
748  dol_syslog("CMailFile::sendfile: mail end error=".$this->error, LOG_ERR);
749  $res=false;
750  }
751  }
752  }
753  else if ($this->sendmode == 'swiftmailer')
754  {
755  // Use Swift Mailer library
756  // ------------------------------------------
757  require_once DOL_DOCUMENT_ROOT.'/includes/swiftmailer/lib/swift_required.php';
758 
759  // Clean parameters
760  if (empty($conf->global->$keyforsmtpserver)) $conf->global->$keyforsmtpserver=ini_get('SMTP');
761  if (empty($conf->global->$keyforsmtpport)) $conf->global->$keyforsmtpport=ini_get('smtp_port');
762 
763  // If we use SSL/TLS
764  $server = $conf->global->$keyforsmtpserver;
765  $secure = '';
766  if (! empty($conf->global->$keyfortls) && function_exists('openssl_open')) $secure='ssl';
767  if (! empty($conf->global->$keyforstarttls) && function_exists('openssl_open')) $secure='tls';
768 
769  $this->transport = new Swift_SmtpTransport($server, $conf->global->$keyforsmtpport, $secure);
770 
771  if (! empty($conf->global->$keyforsmtpid)) $this->transport->setUsername($conf->global->$keyforsmtpid);
772  if (! empty($conf->global->$keyforsmtppw)) $this->transport->setPassword($conf->global->$keyforsmtppw);
773  //$smtps->_msgReplyTo = 'reply@web.com';
774 
775  // Create the Mailer using your created Transport
776  $this->mailer = new Swift_Mailer($this->transport);
777 
778  // DKIM SIGN
779  if ($conf->global->MAIN_MAIL_EMAIL_DKIM_ENABLED) {
780  $privateKey = $conf->global->MAIN_MAIL_EMAIL_DKIM_PRIVATE_KEY;
781  $domainName = $conf->global->MAIN_MAIL_EMAIL_DKIM_DOMAIN;
782  $selector = $conf->global->MAIN_MAIL_EMAIL_DKIM_SELECTOR;
783  $signer = new Swift_Signers_DKIMSigner($privateKey, $domainName, $selector);
784  $this->message->attachSigner($signer->ignoreHeader('Return-Path'));
785  }
786 
787  if (! empty($conf->global->MAIN_MAIL_DEBUG)) {
788  // To use the ArrayLogger
789  $this->logger = new Swift_Plugins_Loggers_ArrayLogger();
790  // Or to use the Echo Logger
791  //$this->logger = new Swift_Plugins_Loggers_EchoLogger();
792  $this->mailer->registerPlugin(new Swift_Plugins_LoggerPlugin($this->logger));
793  }
794  // send mail
795  try {
796  $result = $this->mailer->send($this->message);
797  } catch (Exception $e) {
798  $this->error = $e->getMessage();
799  }
800  if (! empty($conf->global->MAIN_MAIL_DEBUG)) $this->dump_mail();
801 
802  $res = true;
803  if (! empty($this->error) || ! $result) {
804  dol_syslog("CMailFile::sendfile: mail end error=".$this->error, LOG_ERR);
805  $res=false;
806  }
807  else
808  {
809  dol_syslog("CMailFile::sendfile: mail end success", LOG_DEBUG);
810  }
811  }
812  else
813  {
814  // Send mail method not correctly defined
815  // --------------------------------------
816 
817  return 'Bad value for sendmode';
818  }
819 
820  $parameters=array(); $action='';
821  $reshook = $hookmanager->executeHooks('sendMailAfter', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
822  if ($reshook < 0)
823  {
824  $this->error = "Error in hook maildao sendMailAfter " . $reshook;
825  dol_syslog("CMailFile::sendfile: mail end error=" . $this->error, LOG_ERR);
826 
827  return $reshook;
828  }
829  }
830  else
831  {
832  $this->error='No mail sent. Feature is disabled by option MAIN_DISABLE_ALL_MAILS';
833  dol_syslog("CMailFile::sendfile: ".$this->error, LOG_WARNING);
834  }
835 
836  error_reporting($errorlevel); // Reactive niveau erreur origine
837 
838  return $res;
839  }
840 
847  static function encodetorfc2822($stringtoencode)
848  {
849  global $conf;
850  return '=?'.$conf->file->character_set_client.'?B?'.base64_encode($stringtoencode).'?=';
851  }
852 
853  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
860  function _encode_file($sourcefile)
861  {
862  // phpcs:enable
863  $newsourcefile=dol_osencode($sourcefile);
864 
865  if (is_readable($newsourcefile))
866  {
867  $contents = file_get_contents($newsourcefile); // Need PHP 4.3
868  $encoded = chunk_split(base64_encode($contents), 76, $this->eol); // 76 max is defined into http://tools.ietf.org/html/rfc2047
869  return $encoded;
870  }
871  else
872  {
873  $this->error="Error: Can't read file '".$sourcefile."' into _encode_file";
874  dol_syslog("CMailFile::encode_file: ".$this->error, LOG_ERR);
875  return -1;
876  }
877  }
878 
879 
880  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
888  function dump_mail()
889  {
890  // phpcs:enable
891  global $conf,$dolibarr_main_data_root;
892 
893  if (@is_writeable($dolibarr_main_data_root)) // Avoid fatal error on fopen with open_basedir
894  {
895  $outputfile=$dolibarr_main_data_root."/dolibarr_mail.log";
896  $fp = fopen($outputfile,"w");
897 
898  if ($this->sendmode == 'mail')
899  {
900  fputs($fp, $this->headers);
901  fputs($fp, $this->eol); // This eol is added by the mail function, so we add it in log
902  fputs($fp, $this->message);
903  }
904  elseif ($this->sendmode == 'smtps')
905  {
906  fputs($fp, $this->smtps->log); // this->smtps->log is filled only if MAIN_MAIL_DEBUG was set to on
907  }
908  elseif ($this->sendmode == 'swiftmailer')
909  {
910  fputs($fp, $this->logger->dump()); // this->logger is filled only if MAIN_MAIL_DEBUG was set to on
911  }
912 
913  fclose($fp);
914  if (! empty($conf->global->MAIN_UMASK))
915  @chmod($outputfile, octdec($conf->global->MAIN_UMASK));
916  }
917  }
918 
919 
926  function checkIfHTML($msg)
927  {
928  if (!preg_match('/^[\s\t]*<html/i',$msg))
929  {
930  $out = "<html><head><title></title>";
931  if (!empty($this->styleCSS)) $out.= $this->styleCSS;
932  $out.= "</head><body";
933  if (!empty($this->bodyCSS)) $out.= $this->bodyCSS;
934  $out.= ">";
935  $out.= $msg;
936  $out.= "</body></html>";
937  }
938  else
939  {
940  $out = $msg;
941  }
942 
943  return $out;
944  }
945 
951  function buildCSS()
952  {
953  if (! empty($this->css))
954  {
955  // Style CSS
956  $this->styleCSS = '<style type="text/css">';
957  $this->styleCSS.= 'body {';
958 
959  if ($this->css['bgcolor'])
960  {
961  $this->styleCSS.= ' background-color: '.$this->css['bgcolor'].';';
962  $this->bodyCSS.= ' bgcolor="'.$this->css['bgcolor'].'"';
963  }
964  if ($this->css['bgimage'])
965  {
966  // TODO recuperer cid
967  $this->styleCSS.= ' background-image: url("cid:'.$this->css['bgimage_cid'].'");';
968  }
969  $this->styleCSS.= '}';
970  $this->styleCSS.= '</style>';
971  }
972  }
973 
974 
975  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
981  function write_smtpheaders()
982  {
983  // phpcs:enable
984  global $conf;
985  $out = "";
986 
987  $host = dol_getprefix('email');
988 
989  // Sender
990  //$out.= "Sender: ".getValidAddress($this->addr_from,2)).$this->eol2;
991  $out.= "From: ".$this->getValidAddress($this->addr_from,3,1).$this->eol2;
992  if (! empty($conf->global->MAIN_MAIL_SENDMAIL_FORCE_BA))
993  {
994  $out.= "To: ".$this->getValidAddress($this->addr_to,0,1).$this->eol2;
995  }
996  // 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.
997  $out.= "Return-Path: ".$this->getValidAddress($this->addr_from,0,1).$this->eol2;
998  if (isset($this->reply_to) && $this->reply_to) $out.= "Reply-To: ".$this->getValidAddress($this->reply_to,2).$this->eol2;
999  if (isset($this->errors_to) && $this->errors_to) $out.= "Errors-To: ".$this->getValidAddress($this->errors_to,2).$this->eol2;
1000 
1001  // Receiver
1002  if (isset($this->addr_cc) && $this->addr_cc) $out.= "Cc: ".$this->getValidAddress($this->addr_cc,2).$this->eol2;
1003  if (isset($this->addr_bcc) && $this->addr_bcc) $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 ?
1004 
1005  // Delivery receipt
1006  if (isset($this->deliveryreceipt) && $this->deliveryreceipt == 1) $out.= "Disposition-Notification-To: ".$this->getValidAddress($this->addr_from,2).$this->eol2;
1007 
1008  //$out.= "X-Priority: 3".$this->eol2;
1009 
1010  $out.= 'Date: ' . date("r") . $this->eol2;
1011 
1012  $trackid = $this->trackid;
1013  if ($trackid)
1014  {
1015  // References is kept in response and Message-ID is returned into In-Reply-To:
1016  $out.= 'Message-ID: <' . time() . '.phpmail-dolibarr-'. $trackid . '@' . $host . ">" . $this->eol2; // Uppercase seems replaced by phpmail
1017  $out.= 'References: <' . time() . '.phpmail-dolibarr-'. $trackid . '@' . $host . ">" . $this->eol2;
1018  $out.= 'X-Dolibarr-TRACKID: ' . $trackid . '@' . $host. $this->eol2;
1019  }
1020  else
1021  {
1022  $out.= 'Message-ID: <' . time() . '.phpmail@' . $host . ">" . $this->eol2;
1023  }
1024 
1025  if (! empty($_SERVER['REMOTE_ADDR'])) $out.= "X-RemoteAddr: " . $_SERVER['REMOTE_ADDR']. $this->eol2;
1026  $out.= "X-Mailer: Dolibarr version " . DOL_VERSION ." (using php mail)".$this->eol2;
1027  $out.= "Mime-Version: 1.0".$this->eol2;
1028 
1029  //$out.= "From: ".$this->getValidAddress($this->addr_from,3,1).$this->eol;
1030 
1031  $out.= "Content-Type: multipart/mixed;".$this->eol2." boundary=\"".$this->mixed_boundary."\"".$this->eol2;
1032  $out.= "Content-Transfer-Encoding: 8bit".$this->eol2; // TODO Seems to be ignored. Header is 7bit once received.
1033 
1034  dol_syslog("CMailFile::write_smtpheaders smtp_header=\n".$out);
1035  return $out;
1036  }
1037 
1038 
1039  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1047  function write_mimeheaders($filename_list, $mimefilename_list)
1048  {
1049  // phpcs:enable
1050  $mimedone=0;
1051  $out = "";
1052 
1053  if (is_array($filename_list))
1054  {
1055  $filename_list_size=count($filename_list);
1056  for($i=0;$i < $filename_list_size;$i++)
1057  {
1058  if ($filename_list[$i])
1059  {
1060  if ($mimefilename_list[$i]) $filename_list[$i] = $mimefilename_list[$i];
1061  $out.= "X-attachments: $filename_list[$i]".$this->eol2;
1062  }
1063  }
1064  }
1065 
1066  dol_syslog("CMailFile::write_mimeheaders mime_header=\n".$out, LOG_DEBUG);
1067  return $out;
1068  }
1069 
1070  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1077  function write_body($msgtext)
1078  {
1079  // phpcs:enable
1080  global $conf;
1081 
1082  $out='';
1083 
1084  $out.= "--" . $this->mixed_boundary . $this->eol;
1085 
1086  if ($this->atleastoneimage)
1087  {
1088  $out.= "Content-Type: multipart/alternative;".$this->eol." boundary=\"".$this->alternative_boundary."\"".$this->eol;
1089  $out.= $this->eol;
1090  $out.= "--" . $this->alternative_boundary . $this->eol;
1091  }
1092 
1093  // Make RFC821 Compliant, replace bare linefeeds
1094  $strContent = preg_replace("/(?<!\r)\n/si", "\r\n", $msgtext); // PCRE modifier /s means new lines are common chars
1095  if (! empty($conf->global->MAIN_FIX_FOR_BUGGED_MTA))
1096  {
1097  $strContent = preg_replace("/\r\n/si", "\n", $strContent); // PCRE modifier /s means new lines are common chars
1098  }
1099 
1100  $strContentAltText = '';
1101  if ($this->msgishtml)
1102  {
1103  // Similar code to forge a text from html is also in CMailFile.class.php
1104  $strContentAltText = preg_replace("/<br\s*[^>]*>/"," ", $strContent);
1105  $strContentAltText = html_entity_decode(strip_tags($strContentAltText));
1106  $strContentAltText = rtrim(wordwrap($strContentAltText, 75, empty($conf->global->MAIN_FIX_FOR_BUGGED_MTA)?"\r\n":"\n"));
1107 
1108  // Check if html header already in message, if not complete the message
1109  $strContent = $this->checkIfHTML($strContent);
1110  }
1111 
1112  // Make RFC2045 Compliant, split lines
1113  //$strContent = rtrim(chunk_split($strContent)); // Function chunck_split seems ko if not used on a base64 content
1114  // TODO Encode main content into base64 and use the chunk_split, or quoted-printable
1115  $strContent = rtrim(wordwrap($strContent, 75, empty($conf->global->MAIN_FIX_FOR_BUGGED_MTA)?"\r\n":"\n")); // TODO Using this method creates unexpected line break on text/plain content.
1116 
1117  if ($this->msgishtml)
1118  {
1119  if ($this->atleastoneimage)
1120  {
1121  $out.= "Content-Type: text/plain; charset=".$conf->file->character_set_client.$this->eol;
1122  //$out.= "Content-Transfer-Encoding: 7bit".$this->eol;
1123  $out.= $this->eol.($strContentAltText?$strContentAltText:strip_tags($strContent)).$this->eol; // Add plain text message
1124  $out.= "--" . $this->alternative_boundary . $this->eol;
1125  $out.= "Content-Type: multipart/related;".$this->eol." boundary=\"".$this->related_boundary."\"".$this->eol;
1126  $out.= $this->eol;
1127  $out.= "--" . $this->related_boundary . $this->eol;
1128  }
1129 
1130  if (! $this->atleastoneimage && $strContentAltText && ! empty($conf->global->MAIN_MAIL_USE_MULTI_PART)) // Add plain text message part before html part
1131  {
1132  $out.= "Content-Type: multipart/alternative;".$this->eol." boundary=\"".$this->alternative_boundary."\"".$this->eol;
1133  $out.= $this->eol;
1134  $out.= "--" . $this->alternative_boundary . $this->eol;
1135  $out.= "Content-Type: text/plain; charset=".$conf->file->character_set_client.$this->eol;
1136  //$out.= "Content-Transfer-Encoding: 7bit".$this->eol;
1137  $out.= $this->eol.$strContentAltText.$this->eol;
1138  $out.= "--" . $this->alternative_boundary . $this->eol;
1139  }
1140 
1141  $out.= "Content-Type: text/html; charset=".$conf->file->character_set_client.$this->eol;
1142  //$out.= "Content-Transfer-Encoding: 7bit".$this->eol; // TODO Use base64
1143  $out.= $this->eol.$strContent.$this->eol;
1144 
1145  if (! $this->atleastoneimage && $strContentAltText && ! empty($conf->global->MAIN_MAIL_USE_MULTI_PART)) // Add plain text message part after html part
1146  {
1147  $out.= "--" . $this->alternative_boundary . "--". $this->eol;
1148  }
1149  }
1150  else
1151  {
1152  $out.= "Content-Type: text/plain; charset=".$conf->file->character_set_client.$this->eol;
1153  //$out.= "Content-Transfer-Encoding: 7bit".$this->eol;
1154  $out.= $this->eol.$strContent.$this->eol;
1155  }
1156 
1157  $out.= $this->eol;
1158 
1159  // Encode images
1160  if ($this->atleastoneimage)
1161  {
1162  $out .= $this->write_images($this->images_encoded);
1163  // always end related and end alternative after inline images
1164  $out .= "--" . $this->related_boundary . "--" . $this->eol;
1165  $out .= $this->eol . "--" . $this->alternative_boundary . "--" . $this->eol;
1166  $out .= $this->eol;
1167  }
1168 
1169  return $out;
1170  }
1171 
1172  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1181  function write_files($filename_list,$mimetype_list,$mimefilename_list)
1182  {
1183  // phpcs:enable
1184  $out = '';
1185 
1186  $filename_list_size=count($filename_list);
1187  for($i=0;$i < $filename_list_size;$i++)
1188  {
1189  if ($filename_list[$i])
1190  {
1191  dol_syslog("CMailFile::write_files: i=$i");
1192  $encoded = $this->_encode_file($filename_list[$i]);
1193  if ($encoded >= 0)
1194  {
1195  if ($mimefilename_list[$i]) $filename_list[$i] = $mimefilename_list[$i];
1196  if (! $mimetype_list[$i]) {
1197  $mimetype_list[$i] = "application/octet-stream";
1198  }
1199 
1200  $out.= "--" . $this->mixed_boundary . $this->eol;
1201  $out.= "Content-Disposition: attachment; filename=\"".$filename_list[$i]."\"".$this->eol;
1202  $out.= "Content-Type: " . $mimetype_list[$i] . "; name=\"".$filename_list[$i]."\"".$this->eol;
1203  $out.= "Content-Transfer-Encoding: base64".$this->eol;
1204  $out.= "Content-Description: ".$filename_list[$i].$this->eol;
1205  $out.= $this->eol;
1206  $out.= $encoded;
1207  $out.= $this->eol;
1208  //$out.= $this->eol;
1209  }
1210  else
1211  {
1212  return $encoded;
1213  }
1214  }
1215  }
1216 
1217  return $out;
1218  }
1219 
1220 
1221  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1228  function write_images($images_list)
1229  {
1230  // phpcs:enable
1231  $out = '';
1232 
1233  if (is_array($images_list))
1234  {
1235  foreach ($images_list as $img)
1236  {
1237  dol_syslog("CMailFile::write_images: ".$img["name"]);
1238 
1239  $out.= "--" . $this->related_boundary . $this->eol; // always related for an inline image
1240  $out.= "Content-Type: " . $img["content_type"] . "; name=\"".$img["name"]."\"".$this->eol;
1241  $out.= "Content-Transfer-Encoding: base64".$this->eol;
1242  $out.= "Content-Disposition: inline; filename=\"".$img["name"]."\"".$this->eol;
1243  $out.= "Content-ID: <".$img["cid"].">".$this->eol;
1244  $out.= $this->eol;
1245  $out.= $img["image_encoded"];
1246  $out.= $this->eol;
1247  }
1248  }
1249 
1250  return $out;
1251  }
1252 
1253 
1254  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1262  function check_server_port($host,$port)
1263  {
1264  // phpcs:enable
1265  global $conf;
1266 
1267  $_retVal=0;
1268  $timeout=5; // Timeout in seconds
1269 
1270  if (function_exists('fsockopen'))
1271  {
1272  $keyforsmtpserver='MAIN_MAIL_SMTP_SERVER';
1273  $keyforsmtpport ='MAIN_MAIL_SMTP_PORT';
1274  $keyforsmtpid ='MAIN_MAIL_SMTPS_ID';
1275  $keyforsmtppw ='MAIN_MAIL_SMTPS_PW';
1276  $keyfortls ='MAIN_MAIL_EMAIL_TLS';
1277  $keyforstarttls ='MAIN_MAIL_EMAIL_STARTTLS';
1278  if ($this->sendcontext == 'emailing' && !empty($conf->global->MAIN_MAIL_SENDMODE_EMAILING) && $conf->global->MAIN_MAIL_SENDMODE_EMAILING != 'default')
1279  {
1280  $keyforsmtpserver='MAIN_MAIL_SMTP_SERVER_EMAILING';
1281  $keyforsmtpport ='MAIN_MAIL_SMTP_PORT_EMAILING';
1282  $keyforsmtpid ='MAIN_MAIL_SMTPS_ID_EMAILING';
1283  $keyforsmtppw ='MAIN_MAIL_SMTPS_PW_EMAILING';
1284  $keyfortls ='MAIN_MAIL_EMAIL_TLS_EMAILING';
1285  $keyforstarttls ='MAIN_MAIL_EMAIL_STARTTLS_EMAILING';
1286  }
1287 
1288  // If we use SSL/TLS
1289  if (! empty($conf->global->$keyfortls) && function_exists('openssl_open')) $host='ssl://'.$host;
1290  // tls smtp start with no encryption
1291  //if (! empty($conf->global->MAIN_MAIL_EMAIL_STARTTLS) && function_exists('openssl_open')) $host='tls://'.$host;
1292 
1293  dol_syslog("Try socket connection to host=".$host." port=".$port);
1294  //See if we can connect to the SMTP server
1295  if ($socket = @fsockopen(
1296  $host, // Host to test, IP or domain. Add ssl:// for SSL/TLS.
1297  $port, // which Port number to use
1298  $errno, // actual system level error
1299  $errstr, // and any text that goes with the error
1300  $timeout
1301  )) // timeout for reading/writing data over the socket
1302  {
1303  // Windows still does not have support for this timeout function
1304  if (function_exists('stream_set_timeout')) stream_set_timeout($socket, $timeout, 0);
1305 
1306  dol_syslog("Now we wait for answer 220");
1307 
1308  // Check response from Server
1309  if ( $_retVal = $this->server_parse($socket, "220") ) $_retVal = $socket;
1310  }
1311  else
1312  {
1313  $this->error = utf8_check('Error '.$errno.' - '.$errstr)?'Error '.$errno.' - '.$errstr:utf8_encode('Error '.$errno.' - '.$errstr);
1314  }
1315  }
1316  return $_retVal;
1317  }
1318 
1319  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1328  function server_parse($socket, $response)
1329  {
1330  // phpcs:enable
1331  $_retVal = true; // Indicates if Object was created or not
1332  $server_response = '';
1333 
1334  while (substr($server_response,3,1) != ' ')
1335  {
1336  if (! ($server_response = fgets($socket, 256)) )
1337  {
1338  $this->error="Couldn't get mail server response codes";
1339  return false;
1340  }
1341  }
1342 
1343  if( !( substr($server_response, 0, 3) == $response ) )
1344  {
1345  $this->error="Ran into problems sending Mail.\r\nResponse: $server_response";
1346  $_retVal = false;
1347  }
1348 
1349  return $_retVal;
1350  }
1351 
1358  function findHtmlImages($images_dir)
1359  {
1360  // Build the list of image extensions
1361  $extensions = array_keys($this->image_types);
1362 
1363  $matches = array();
1364  preg_match_all('/(?:"|\')([^"\']+\.('.implode('|', $extensions).'))(?:"|\')/Ui', $this->html, $matches); // If "xxx.ext" or 'xxx.ext' found
1365 
1366  if (! empty($matches))
1367  {
1368  $i=0;
1369  foreach ($matches[1] as $full)
1370  {
1371 
1372  if (preg_match('/file=([A-Za-z0-9_\-\/]+[\.]?[A-Za-z0-9]+)?$/i',$full,$regs)) // If xxx is 'file=aaa'
1373  {
1374  $img = $regs[1];
1375 
1376  if (file_exists($images_dir.'/'.$img))
1377  {
1378  // Image path in src
1379  $src = preg_quote($full,'/');
1380 
1381  // Image full path
1382  $this->html_images[$i]["fullpath"] = $images_dir.'/'.$img;
1383 
1384  // Image name
1385  $this->html_images[$i]["name"] = $img;
1386 
1387  // Content type
1388  if (preg_match('/^.+\.(\w{3,4})$/', $img, $reg))
1389  {
1390  $ext=strtolower($reg[1]);
1391  $this->html_images[$i]["content_type"] = $this->image_types[$ext];
1392  }
1393 
1394  // cid
1395  $this->html_images[$i]["cid"] = dol_hash(uniqid(time()), 3); // Force md5 hash (does not contains special chars)
1396  $this->html = preg_replace("/src=\"$src\"|src='$src'/i", "src=\"cid:".$this->html_images[$i]["cid"]."\"", $this->html);
1397  }
1398  $i++;
1399  }
1400  }
1401 
1402  if (!empty($this->html_images))
1403  {
1404  $inline = array();
1405 
1406  $i=0;
1407 
1408  foreach ($this->html_images as $img)
1409  {
1410  $fullpath = $images_dir.'/'.$img["name"];
1411 
1412  // If duplicate images are embedded, they may show up as attachments, so remove them.
1413  if (!in_array($fullpath,$inline))
1414  {
1415  // Read image file
1416  if ($image = file_get_contents($fullpath))
1417  {
1418  // On garde que le nom de l'image
1419  preg_match('/([A-Za-z0-9_-]+[\.]?[A-Za-z0-9]+)?$/i',$img["name"],$regs);
1420  $imgName = $regs[1];
1421 
1422  $this->images_encoded[$i]['name'] = $imgName;
1423  $this->images_encoded[$i]['fullpath'] = $fullpath;
1424  $this->images_encoded[$i]['content_type'] = $img["content_type"];
1425  $this->images_encoded[$i]['cid'] = $img["cid"];
1426  // Encodage de l'image
1427  $this->images_encoded[$i]["image_encoded"] = chunk_split(base64_encode($image), 68, $this->eol);
1428  $inline[] = $fullpath;
1429  }
1430  }
1431  $i++;
1432  }
1433  }
1434  else
1435  {
1436  return -1;
1437  }
1438 
1439  return 1;
1440  }
1441  else
1442  {
1443  return 0;
1444  }
1445  }
1446 
1460  static function getValidAddress($address,$format,$encode=0,$maxnumberofemail=0)
1461  {
1462  global $conf;
1463 
1464  $ret='';
1465 
1466  $arrayaddress=explode(',',$address);
1467 
1468  // Boucle sur chaque composant de l'adresse
1469  $i=0;
1470  foreach($arrayaddress as $val)
1471  {
1472  if (preg_match('/^(.*)<(.*)>$/i',trim($val),$regs))
1473  {
1474  $name = trim($regs[1]);
1475  $email = trim($regs[2]);
1476  }
1477  else
1478  {
1479  $name = '';
1480  $email = trim($val);
1481  }
1482 
1483  if ($email)
1484  {
1485  $i++;
1486 
1487  $newemail='';
1488  if ($format == 4)
1489  {
1490  $newemail = $name?$name:$email;
1491  }
1492  if ($format == 2)
1493  {
1494  $newemail=$email;
1495  }
1496  if ($format == 1 || $format == 3)
1497  {
1498  $newemail='<'.$email.'>';
1499  }
1500  if ($format == 0 || $format == 3)
1501  {
1502  if (! empty($conf->global->MAIN_MAIL_NO_FULL_EMAIL)) $newemail='<'.$email.'>';
1503  elseif (! $name) $newemail='<'.$email.'>';
1504  else $newemail=($format==3?'"':'').($encode?self::encodetorfc2822($name):$name).($format==3?'"':'').' <'.$email.'>';
1505  }
1506 
1507  $ret=($ret ? $ret.',' : '').$newemail;
1508 
1509  // Stop if we have too much records
1510  if ($maxnumberofemail && $i >= $maxnumberofemail)
1511  {
1512  if (count($arrayaddress) > $maxnumberofemail) $ret.='...';
1513  break;
1514  }
1515  }
1516  }
1517 
1518  return $ret;
1519  }
1520 
1527  function getArrayAddress($address)
1528  {
1529  global $conf;
1530 
1531  $ret=array();
1532 
1533  $arrayaddress=explode(',',$address);
1534 
1535  // Boucle sur chaque composant de l'adresse
1536  foreach($arrayaddress as $val)
1537  {
1538  if (preg_match('/^(.*)<(.*)>$/i',trim($val),$regs))
1539  {
1540  $name = trim($regs[1]);
1541  $email = trim($regs[2]);
1542  }
1543  else
1544  {
1545  $name = null;
1546  $email = trim($val);
1547  }
1548 
1549  $ret[$email]=empty($conf->global->MAIN_MAIL_NO_FULL_EMAIL)?$name:null;
1550  }
1551 
1552  return $ret;
1553  }
1554 }
checkIfHTML($msg)
Correct an uncomplete html string.
dol_osencode($str)
Return a string encoded into OS filesystem encoding.
write_body($msgtext)
Return email content (mode = &#39;mail&#39;)
findHtmlImages($images_dir)
Seearch images into html message and init array this->images_encoded if found.
getArrayAddress($address)
Return a formatted array of address string for SMTP protocol.
Class to construct and send SMTP compliant email, even to a secure SMTP server, regardless of platfor...
Definition: smtps.class.php:46
write_images($images_list)
Attach an image to email (mode = &#39;mail&#39;)
write_mimeheaders($filename_list, $mimefilename_list)
Create header MIME (mode = &#39;mail&#39;)
__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='')
CMailFile.
write_files($filename_list, $mimetype_list, $mimefilename_list)
Attach file to email (mode = &#39;mail&#39;)
$bodyCSS
Defined background directly in body tag.
Class to manage hooks.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='')
Write log message into outputs.
server_parse($socket, $response)
This function has been modified as provided by SirSir to allow multiline responses when using SMTP Ex...
static getValidAddress($address, $format, $encode=0, $maxnumberofemail=0)
Return a formatted address string for SMTP protocol.
Class to send emails (with attachments or not) Usage: $mailfile = new CMailFile($subject,$sendto,$replyto,$message,$filepath,$mimetype,$filename,$cc,$ccc,$deliveryreceipt,$msgishtml,$errors_to,$css,$trackid,$moreinheader,$sendcontext); $mailfile->sendfile();.
$styleCSS
Defined css style for body background.
if(GETPOST('cancel', 'alpha')) if(! GETPOST( 'confirmmassaction', 'alpha') &&$massaction !='presend' &&$massaction !='confirm_presend')
Draft customers invoices.
Definition: list.php:156
utf8_check($str)
Check if a string is in UTF8.
dump_mail()
Write content of a SMTP request into a dump file (mode = all) Used for debugging. ...
check_server_port($host, $port)
Try to create a socket connection.
static encodetorfc2822($stringtoencode)
Encode subject according to RFC 2822 - http://en.wikipedia.org/wiki/MIME#Encoded-Word.
sendfile()
Send mail that was prepared by constructor.
_encode_file($sourcefile)
Read a file on disk and return encoded content for emails (mode = &#39;mail&#39;)
dol_hash($chain, $type='0')
Returns a hash of a string.
write_smtpheaders()
Create SMTP headers (mode = &#39;mail&#39;)
buildCSS()
Build a css style (mode = all) into this->styleCSS and this->bodyCSS.
dol_textishtml($msg, $option=0)
Return if a text is a html content.