PageRenderTime 127ms CodeModel.GetById 9ms RepoModel.GetById 0ms app.codeStats 0ms

/modules/sender/lib/integration/sender/mail/transportmail.php

https://gitlab.com/alexprowars/bitrix
PHP | 500 lines | 334 code | 59 blank | 107 comment | 28 complexity | 312a5fef297610c0de5aa32fee8635a0 MD5 | raw file
  1. <?php
  2. /**
  3. * Bitrix Framework
  4. * @package bitrix
  5. * @subpackage sender
  6. * @copyright 2001-2012 Bitrix
  7. */
  8. namespace Bitrix\Sender\Integration\Sender\Mail;
  9. use Bitrix\Main;
  10. use Bitrix\Main\Config\Option;
  11. use Bitrix\Main\IO\File;
  12. use Bitrix\Main\Localization\Loc;
  13. use Bitrix\Main\Mail;
  14. use Bitrix\Main\Result;
  15. use Bitrix\Sender\Consent;
  16. use Bitrix\Sender\Integration;
  17. use Bitrix\Sender\Message;
  18. use Bitrix\Sender\Recipient;
  19. use Bitrix\Sender\Runtime\Env;
  20. use Bitrix\Sender\Transport;
  21. use Bitrix\Sender\Security;
  22. Loc::loadMessages(__FILE__);
  23. /**
  24. * Class TransportMail
  25. * @package Bitrix\Sender\Integration\Sender\Mail
  26. */
  27. class TransportMail implements Transport\iBase, Transport\iDuration, Transport\iLimitation, Transport\iConsent
  28. {
  29. const CODE = self::CODE_MAIL;
  30. /** @var Message\Configuration $configuration Configuration. */
  31. protected $configuration;
  32. /** @var Mail\Context $mailContext Mail context. */
  33. protected $mailContext;
  34. /** @var Mail\Address $mailAddress Mail address. */
  35. protected $mailAddress;
  36. /**
  37. * TransportMail constructor.
  38. */
  39. public function __construct()
  40. {
  41. $this->configuration = new Message\Configuration();
  42. }
  43. /**
  44. * Get name.
  45. *
  46. * @return string
  47. */
  48. public function getName()
  49. {
  50. return Loc::getMessage('SENDER_INTEGRATION_MAIL_TRANSPORT_NAME');
  51. }
  52. /**
  53. * Get code.
  54. *
  55. * @return string
  56. */
  57. public function getCode()
  58. {
  59. return self::CODE;
  60. }
  61. /**
  62. * Get supported recipient types.
  63. *
  64. * @return integer[]
  65. */
  66. public function getSupportedRecipientTypes()
  67. {
  68. return array(Recipient\Type::EMAIL);
  69. }
  70. /**
  71. * Load configuration.
  72. *
  73. * @param string|null $id ID.
  74. *
  75. * @return Message\Configuration
  76. */
  77. public function loadConfiguration($id = null)
  78. {
  79. return $this->configuration;
  80. }
  81. /**
  82. * Save configuration.
  83. *
  84. * @param Message\Configuration $configuration Configuration.
  85. *
  86. * @return Result|null
  87. */
  88. public function saveConfiguration(Message\Configuration $configuration)
  89. {
  90. return null;
  91. }
  92. /**
  93. * Start.
  94. *
  95. * @return void
  96. */
  97. public function start()
  98. {
  99. }
  100. /**
  101. * Send.
  102. *
  103. * @param Message\Adapter $message Message.
  104. *
  105. * @return bool
  106. */
  107. public function send(Message\Adapter $message)
  108. {
  109. $headers = $message->getConfiguration()->get('HEADERS');
  110. $headers = is_array($headers) ? $headers : array();
  111. $fields = $message->getFields();
  112. $preparedConsentLink = '';
  113. $unsubLink = $message->getUnsubTracker()->getLink();
  114. if (!isset($fields['UNSUBSCRIBE_LINK']))
  115. {
  116. $fields['UNSUBSCRIBE_LINK'] = $unsubLink;
  117. }
  118. if ($unsubLink)
  119. {
  120. if (!preg_match('/^http:|https:/', $unsubLink))
  121. {
  122. $unsubLink = $this->getSenderLinkProtocol() . '://' . $message->getSiteServerName() . $unsubLink;
  123. }
  124. $headers['List-Unsubscribe'] = '<'.$unsubLink.'>';
  125. }
  126. $fields['SENDER_MAIL_CHARSET'] = $message->getCharset();
  127. if (Integration\Bitrix24\Service::isCloud())
  128. {
  129. $headers['X-Bitrix-Mail-Count'] = $message->getTransport()->getSendCount() ?: 1;
  130. $recipientData = $message->getRecipientData();
  131. if ($recipientData['CONTACT_IS_SEND_SUCCESS'] !== 'Y')
  132. {
  133. $headers['X-Bitrix-Mail-Unverified'] = 1;
  134. }
  135. }
  136. $linkParameters = $message->getConfiguration()->get('LINK_PARAMS');
  137. if($linkParameters)
  138. {
  139. $parametersTmp = [];
  140. parse_str($linkParameters, $parametersTmp);
  141. if(is_array($parametersTmp))
  142. {
  143. $clickUriParameters = $message->getClickTracker()->getUriParameters();
  144. $message->getClickTracker()->setUriParameters(
  145. array_merge($clickUriParameters, $parametersTmp)
  146. );
  147. }
  148. }
  149. $mailAttachment = array();
  150. $messageAttachment = $message->getConfiguration()->get('ATTACHMENT');
  151. $messageAttachment = is_array($messageAttachment) ? $messageAttachment : array();
  152. foreach ($messageAttachment as $key => $file)
  153. {
  154. if (is_numeric($file) && $file > 0)
  155. {
  156. continue;
  157. }
  158. if (is_array($file) && File::isFileExists($file['tmp_name']))
  159. {
  160. $mailAttachment[] = array(
  161. 'PATH' => $file['tmp_name'],
  162. 'ID' => md5($file['tmp_name']),
  163. 'CONTENT_TYPE' => File::getFileContents($file['tmp_name']),
  164. 'NAME' => ($file['name'] ?: 'some_file'),
  165. );
  166. }
  167. unset($messageAttachment[$key]);
  168. }
  169. //set callback entity Id
  170. if (Integration\Bitrix24\Service::isCloud())
  171. {
  172. if ($message->getRecipientId())
  173. {
  174. $this->getMailContext()->getCallback()
  175. ->setEntityType('rcpt')
  176. ->setEntityId($message->getRecipientId());
  177. }
  178. else
  179. {
  180. $this->getMailContext()->getCallback()
  181. ->setEntityType('test')
  182. ->setEntityId(time() . '.' . rand(100, 1000));
  183. }
  184. }
  185. $canTrackMail = $message->getConfiguration()->get('TRACK_MAIL', $this->canTrackMails());
  186. $mailMessageParams = array(
  187. 'EVENT' => [],
  188. 'FIELDS' => $fields,
  189. 'MESSAGE' => array(
  190. 'BODY_TYPE' => 'html',
  191. 'EMAIL_FROM' => $this->getCleanMailAddress($message->getConfiguration()->get('EMAIL_FROM')),
  192. 'EMAIL_TO' => '#EMAIL_TO#',
  193. 'PRIORITY' => $message->getConfiguration()->get('PRIORITY'),
  194. 'SUBJECT' => $message->getConfiguration()->get('SUBJECT'),
  195. 'MESSAGE' => str_replace('#CONSENT_LINK#', $preparedConsentLink, $message->getConfiguration()->get('BODY')),
  196. 'MESSAGE_PHP' => $message->getConfiguration()->get('BODY_PHP'),
  197. 'FILE' => $messageAttachment
  198. ),
  199. 'SITE' => $message->getSiteId(),
  200. 'CHARSET' => $message->getCharset(),
  201. );
  202. $mailMessage = Mail\EventMessageCompiler::createInstance($mailMessageParams);
  203. $mailMessage->compile();
  204. if (is_array($mailMessage->getMailAttachment()))
  205. {
  206. $mailAttachment = array_merge($mailAttachment, $mailMessage->getMailAttachment());
  207. }
  208. $mailParams = array(
  209. 'TO' => $mailMessage->getMailTo(),
  210. 'SUBJECT' => static::replaceTemplate($mailMessage->getMailSubject()),
  211. 'BODY' => $mailMessage->getMailBody(),
  212. 'HEADER' => $mailMessage->getMailHeaders() + $headers,
  213. 'CHARSET' => $mailMessage->getMailCharset(),
  214. 'CONTENT_TYPE' => $mailMessage->getMailContentType(),
  215. 'MESSAGE_ID' => '',
  216. 'ATTACHMENT' => $mailAttachment,
  217. 'LINK_PROTOCOL' => $this->getSenderLinkProtocol(),
  218. 'LINK_DOMAIN' => $message->getSiteServerName(),
  219. 'TRACK_READ' => $canTrackMail ? $message->getReadTracker()->getArray() : null,
  220. 'TRACK_CLICK' => $canTrackMail ? $message->getClickTracker()->getArray() : null,
  221. 'CONTEXT' => $this->getMailContext(),
  222. );
  223. $linkDomain = $message->getReadTracker()->getLinkDomain();
  224. if ($linkDomain)
  225. {
  226. $mailParams['LINK_DOMAIN'] = $linkDomain;
  227. }
  228. // event on sending email
  229. $eventMailParams = $mailParams;
  230. $eventMailParams['MAILING_CHAIN_ID'] = $message->getConfiguration()->get('LETTER_ID');
  231. $event = new Main\Event('sender', 'OnPostingSendRecipientEmail', [$eventMailParams]);
  232. $event->send();
  233. foreach ($event->getResults() as $eventResult)
  234. {
  235. if($eventResult->getType() == Main\EventResult::ERROR)
  236. {
  237. return false;
  238. }
  239. if(is_array($eventResult->getParameters()))
  240. {
  241. $eventMailParams = array_merge($eventMailParams, $eventResult->getParameters());
  242. }
  243. }
  244. unset($eventMailParams['MAILING_CHAIN_ID']);
  245. $mailParams = $eventMailParams;
  246. return Mail\Mail::send($mailParams);
  247. }
  248. /**
  249. * End.
  250. *
  251. * @return void
  252. */
  253. public function end()
  254. {
  255. }
  256. /**
  257. * Get send duration in seconds.
  258. *
  259. * @param Message\Adapter|null $message Message.
  260. *
  261. * @return float
  262. */
  263. public function getDuration(Message\Adapter $message = null)
  264. {
  265. return 0.01;
  266. }
  267. /**
  268. * Get limiters.
  269. *
  270. * @param Message\iBase $message Message.
  271. * @return Transport\iLimiter[]
  272. */
  273. public function getLimiters(Message\iBase $message = null)
  274. {
  275. $limiters = Integration\Bitrix24\Limitation\Limiter::getList();
  276. if (Integration\Bitrix24\Service::isCloud())
  277. {
  278. $limiters[] = Integration\Bitrix24\Limitation\Limiter::getPortalVerification();
  279. }
  280. if ($message)
  281. {
  282. $limiters[] = self::getTimeLimiter($message);
  283. $email = $message->getConfiguration()->get('EMAIL_FROM');
  284. $address = new \Bitrix\Main\Mail\Address($email);
  285. $limiters[] = Integration\Bitrix24\Limitation\Limiter::getEmailMonthly($address->getEmail());
  286. }
  287. return $limiters;
  288. }
  289. /**
  290. * Return daily limiter.
  291. *
  292. * @return Transport\iLimiter
  293. */
  294. private static function getTimeLimiter($message)
  295. {
  296. return Transport\TimeLimiter::create()
  297. ->withLetter($message);
  298. }
  299. protected function getSenderLinkProtocol()
  300. {
  301. $protocol = Option::get('sender', 'link_protocol', null);
  302. $protocol = $protocol ?: (Integration\Bitrix24\Service::isCloud() ? 'https' : 'http');
  303. return $protocol;
  304. }
  305. protected function canTrackMails()
  306. {
  307. return Option::get('sender', 'track_mails') === 'Y';
  308. }
  309. protected function getMailContext()
  310. {
  311. if (!$this->mailContext)
  312. {
  313. $this->mailContext = new Mail\Context();
  314. $this->mailContext->setCategory(Mail\Context::CAT_EXTERNAL);
  315. $this->mailContext->setPriority(Mail\Context::PRIORITY_LOW);
  316. $this->mailContext->setKeepAlive(Mail\Smtp\Mailer::KEEP_ALIVE_ALWAYS);
  317. if (Integration\Bitrix24\Service::isCloud())
  318. {
  319. $this->mailContext->setCallback(
  320. (new Mail\Callback\Config())->setModuleId('sender')
  321. );
  322. }
  323. }
  324. return $this->mailContext;
  325. }
  326. /**
  327. * Get clean address.
  328. *
  329. * @param string $address Address.
  330. * @return string|null
  331. */
  332. protected function getCleanMailAddress($address)
  333. {
  334. if (!$this->mailAddress)
  335. {
  336. $this->mailAddress = new Mail\Address();
  337. }
  338. return $this->mailAddress->set($address)->get();
  339. }
  340. /**
  341. * @param string|null $str
  342. * @return array|string|string[]|null
  343. */
  344. public static function replaceTemplate(?string $str)
  345. {
  346. preg_match_all("/#([0-9a-zA-Z_.|]+?)#/", $str, $matchesFindPlaceHolders);
  347. if(!empty($matchesFindPlaceHolders) && isset($matchesFindPlaceHolders[1]))
  348. {
  349. foreach($matchesFindPlaceHolders[1] as $key)
  350. {
  351. $str = str_replace("#".$key."#", '', $str);
  352. }
  353. }
  354. return $str;
  355. }
  356. /**
  357. * send Consent Message to Recipient
  358. * @param Message\Adapter $message
  359. * @param Consent\AbstractConsentMessageBuilder $builder
  360. *
  361. * @return bool
  362. */
  363. public function sendConsent(Message\Adapter $message, Consent\AbstractConsentMessageBuilder $builder)
  364. {
  365. $agreement = $this->getAgreement((int)$message->getConfiguration()->get('APPROVE_CONFIRMATION_CONSENT'));
  366. if (!$agreement)
  367. {
  368. return false;
  369. }
  370. $builder->set('POSTING_ID', $message->getId());
  371. $builder->set('CONSENT_ID', $agreement->getId());
  372. $buildedMessage = $builder->buildMessage();
  373. $contentBody = Security\Sanitizer::fixReplacedStyles($agreement->getText());
  374. $contentBody = Security\Sanitizer::sanitizeHtml($contentBody, $agreement->getText());
  375. $template = \Bitrix\Sender\Preset\Templates\Consent::getTemplateHtml();
  376. $body = \Bitrix\Sender\Preset\Templates\Consent::replaceTemplateHtml($template, [
  377. 'APPROVE_BTN_TEXT' => $agreement->getLabelText(),
  378. 'CONSENT_BODY' => $contentBody,
  379. 'CONSENT_FOOTER' => '',
  380. 'APPLY_URL' => $buildedMessage['C_FIELDS']['SENDER_CONSENT_APPLY'],
  381. 'REJECT_URL' => $buildedMessage['C_FIELDS']['SENDER_CONSENT_REJECT'],
  382. ]);
  383. $mailMessageParams = array(
  384. 'EVENT' => [],
  385. 'FIELDS' => [],
  386. 'MESSAGE' => array(
  387. 'BODY_TYPE' => 'html',
  388. 'EMAIL_FROM' => $this->getCleanMailAddress($message->getConfiguration()->get('EMAIL_FROM')),
  389. 'EMAIL_TO' => $buildedMessage['C_FIELDS']['EMAIL'],
  390. 'PRIORITY' => $message->getConfiguration()->get('PRIORITY'),
  391. 'SUBJECT' => Loc::getMessage('SENDER_INTEGRATION_MAIL_CONSENT_SUBJECT'),
  392. 'MESSAGE' => $body,
  393. 'MESSAGE_PHP' => $message->getConfiguration()->get('BODY_PHP'),
  394. ),
  395. 'SITE' => $message->getSiteId(),
  396. 'CHARSET' => $message->getCharset(),
  397. );
  398. $mailMessage = Mail\EventMessageCompiler::createInstance($mailMessageParams);
  399. $mailMessage->compile();
  400. $mailParams = array(
  401. 'TO' => $mailMessage->getMailTo(),
  402. 'SUBJECT' => static::replaceTemplate($mailMessage->getMailSubject()),
  403. 'BODY' => $mailMessage->getMailBody(),
  404. 'HEADER' => $mailMessage->getMailHeaders(),
  405. 'CHARSET' => $mailMessage->getMailCharset(),
  406. 'CONTENT_TYPE' => $mailMessage->getMailContentType(),
  407. 'MESSAGE_ID' => '',
  408. 'CONTEXT' => $this->getMailContext(),
  409. );
  410. return Mail\Mail::send($mailParams);
  411. }
  412. private function getAgreement(int $agreementId): ?Main\UserConsent\Agreement
  413. {
  414. $agreement = new Main\UserConsent\Agreement($agreementId, ['fields' => ['IP']]);
  415. if (!$agreement->isActive() || !$agreement->isExist())
  416. {
  417. return null;
  418. }
  419. return $agreement;
  420. }
  421. private function getAgreementUri(int $agreementId): ?string
  422. {
  423. return (string)\Bitrix\Main\UserConsent\AgreementLink::getUri($agreementId, [], '/pub/agreement.php');
  424. }
  425. /**
  426. * check if consent Option is turn on
  427. * @return bool
  428. */
  429. public function isConsentNeed()
  430. {
  431. return Env::isTransportNeedConsent(static::CODE);
  432. }
  433. /**
  434. * get max consent request num
  435. * @return int
  436. */
  437. public function getConsentMaxRequests(): int
  438. {
  439. return Env::getMaxConsentRequests(static::CODE);
  440. }
  441. }