Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
sender.php
1<?php
2
3namespace Bitrix\Main\Mail;
4
11
12class Sender
13{
14 public const MAIN_SENDER_SMTP_LIMIT_DECREASE = 'MainSenderSmtpLimitDecrease';
15
16 public static function add(array $fields)
17 {
18 if (empty($fields['OPTIONS']) || !is_array($fields['OPTIONS']))
19 {
20 $fields['OPTIONS'] = array();
21 }
22
23 self::checkEmail($fields, $error, $errors);
24 if ($error || $errors)
25 {
26 return array('error' => $error, 'errors' => $errors);
27 }
28
29 if (empty($fields['IS_CONFIRMED']))
30 {
31 $fields['OPTIONS']['confirm_code'] = \Bitrix\Main\Security\Random::getStringByCharsets(5, '0123456789abcdefghjklmnpqrstuvwxyz');
32 $fields['OPTIONS']['confirm_time'] = time();
33 }
34
35 $senderId = 0;
36 $result = Internal\SenderTable::add($fields);
37 if ($result->isSuccess())
38 {
39 $senderId = $result->getId();
40 }
41
42 if (empty($fields['IS_CONFIRMED']))
43 {
44 $mailEventFields = array(
45 'DEFAULT_EMAIL_FROM' => $fields['EMAIL'],
46 'EMAIL_TO' => $fields['EMAIL'],
47 'MESSAGE_SUBJECT' => getMessage('MAIN_MAIL_CONFIRM_MESSAGE_SUBJECT'),
48 'CONFIRM_CODE' => mb_strtoupper($fields['OPTIONS']['confirm_code']),
49 );
50
51 if (!empty($smtpConfig))
52 {
53 \Bitrix\Main\EventManager::getInstance()->addEventHandlerCompatible(
54 'main',
55 'OnBeforeEventSend',
56 function (&$eventFields, &$message, $context) use (&$smtpConfig)
57 {
58 $context->setSmtp($smtpConfig);
59 }
60 );
61 }
62
63 \CEvent::sendImmediate('MAIN_MAIL_CONFIRM_CODE', SITE_ID, $mailEventFields);
64 }
65 else
66 {
67 if (isset($fields['OPTIONS']['__replaces']) && $fields['OPTIONS']['__replaces'] > 0)
68 {
69 Internal\SenderTable::delete(
70 (int) $fields['OPTIONS']['__replaces']
71 );
72 }
73 }
74
75 return ['senderId' => $senderId, 'confirmed' => !empty($fields['IS_CONFIRMED'])];
76 }
77
84 public static function checkEmail(&$fields, &$error = null, Main\ErrorCollection &$errors = null)
85 {
86
87 if (empty($fields['IS_CONFIRMED']) && !empty($fields['OPTIONS']['smtp']))
88 {
89 $smtpConfig = $fields['OPTIONS']['smtp'];
90 $smtpConfig = new Smtp\Config(array(
91 'from' => $fields['EMAIL'],
92 'host' => $smtpConfig['server'],
93 'port' => $smtpConfig['port'],
94 'protocol' => $smtpConfig['protocol'],
95 'login' => $smtpConfig['login'],
96 'password' => $smtpConfig['password'],
97 'isOauth' => $smtpConfig['isOauth'] ?? false,
98 ));
99
100 if ($smtpConfig->canCheck())
101 {
102 if ($smtpConfig->check($error, $errors))
103 {
104 $fields['IS_CONFIRMED'] = true;
105 }
106 }
107 }
108 }
109
110 public static function confirm($ids)
111 {
112 if (!empty($ids))
113 {
114 $res = Internal\SenderTable::getList(array(
115 'filter' => array(
116 '@ID' => (array) $ids,
117 ),
118 ));
119
120 while ($item = $res->fetch())
121 {
122 Internal\SenderTable::update(
123 (int) $item['ID'],
124 array(
125 'IS_CONFIRMED' => true,
126 )
127 );
128
129 if (isset($item['OPTIONS']['__replaces']) && $item['OPTIONS']['__replaces'] > 0)
130 {
131 Internal\SenderTable::delete(
132 (int) $item['OPTIONS']['__replaces']
133 );
134 }
135 }
136 }
137 }
138
139 public static function delete($ids)
140 {
141 $userId = CurrentUser::get()->getId();
142
143 if(!is_array($ids))
144 {
145 $ids = [$ids];
146 }
147 if(empty($ids))
148 {
149 return;
150 }
151 $smtpConfigs = [];
152
153 $senders = SenderTable::getList([
154 'order' => [
155 'ID' => 'desc',
156 ],
157 'filter' => [
158 '=USER_ID' => $userId,
159 '@ID' => $ids,
160 'IS_CONFIRMED' => true]
161 ]
162 )->fetchAll();
163
164 $userFormattedName = CurrentUser::get()->getFormattedName();
165 foreach ($senders as $sender)
166 {
167 if (Loader::includeModule('mail') && $userId)
168 {
169 $senderName = sprintf(
170 '%s <%s>',
171 empty($sender['NAME']) ? $userFormattedName : $sender['NAME'],
172 $sender['EMAIL'],
173 );
174
175 $signatures = UserSignatureTable::getList([
176 'select' => ['ID'],
177 'filter' => [
178 '=USER_ID' => $userId,
179 'SENDER' => $senderName
180 ],
181 ])->fetchAll();
182
183 foreach ($signatures as $signature)
184 {
185 UserSignatureTable::delete($signature['ID']);
186 }
187 }
188
189 if(!empty($sender['OPTIONS']['smtp']['server']) && empty($sender['OPTIONS']['smtp']['encrypted']) && !isset($smtpConfigs[$sender['EMAIL']]))
190 {
191 $smtpConfigs[$sender['EMAIL']] = $sender['OPTIONS']['smtp'];
192 }
193 }
194 if(!empty($smtpConfigs))
195 {
196 $senders = SenderTable::getList([
197 'order' => [
198 'ID' => 'desc',
199 ],
200 'filter' => [
201 '@EMAIL' => array_keys($smtpConfigs),
202 '!ID' => $ids
203 ]
204 ])->fetchAll();
205 foreach($senders as $sender)
206 {
207 if(isset($smtpConfigs[$sender['EMAIL']]))
208 {
209 $options = $sender['OPTIONS'];
210 $options['smtp'] = $smtpConfigs[$sender['EMAIL']];
211 $result = SenderTable::update($sender['ID'], [
212 'OPTIONS' => $options,
213 ]);
214 if($result->isSuccess())
215 {
216 unset($smtpConfigs[$sender['EMAIL']]);
217 static::clearCustomSmtpCache($sender['EMAIL']);
218 }
219 if(empty($smtpConfigs))
220 {
221 break;
222 }
223 }
224 }
225 }
226 foreach ((array) $ids as $id)
227 {
228 Internal\SenderTable::delete(
229 (int) $id
230 );
231 }
232 }
233
234 public static function clearCustomSmtpCache($email)
235 {
236 $cache = new \CPHPCache();
237 $cache->clean($email, '/main/mail/smtp');
238 }
239
240 public static function getCustomSmtp($email)
241 {
242 static $smtp = array();
243
244 if (!isset($smtp[$email]))
245 {
246 $config = false;
247
248 $cache = new \CPHPCache();
249
250 if ($cache->initCache(30*24*3600, $email, '/main/mail/smtp'))
251 {
252 $config = $cache->getVars();
253 }
254 else
255 {
256 $res = Internal\SenderTable::getList(array(
257 'filter' => array(
258 'IS_CONFIRMED' => true,
259 '=EMAIL' => $email,
260 ),
261 'order' => array(
262 'ID' => 'DESC',
263 ),
264 ));
265 while ($item = $res->fetch())
266 {
267 if (!empty($item['OPTIONS']['smtp']['server']) && empty($item['OPTIONS']['smtp']['encrypted']))
268 {
269 $config = $item['OPTIONS']['smtp'];
270 break;
271 }
272 }
273
274 $cache->startDataCache();
275 $cache->endDataCache($config);
276 }
277
278 if ($config)
279 {
280 $config = new Smtp\Config(array(
281 'from' => $email,
282 'host' => $config['server'],
283 'port' => $config['port'],
284 'protocol' => $config['protocol'],
285 'login' => $config['login'],
286 'password' => $config['password'],
287 'isOauth' => $config['isOauth'],
288 ));
289 if ($config->getIsOauth() && \CModule::includeModule('mail'))
290 {
291 $expireGapSeconds = self::getOAuthTokenExpireGapSeconds();
292 $token = \Bitrix\Mail\Helper\OAuth::getTokenByMeta($config->getPassword(), $expireGapSeconds);
293 $config->setPassword($token);
294 }
295 }
296
297 $smtp[$email] = $config;
298 }
299
300 return $smtp[$email];
301 }
302
311 public static function getEmailLimit($email): ?int
312 {
313 $address = new \Bitrix\Main\Mail\Address($email);
314
315 if (!$address->validate())
316 {
317 return null;
318 }
319
320 $email = $address->getEmail();
321 static $mailLimit = array();
322
323 if (!isset($mailLimit[$email]))
324 {
325 $cache = new \CPHPCache();
326
327 if ($cache->initCache(3600, $email, '/main/mail/limit'))
328 {
329 $mailLimit[$email] = $cache->getVars();
330 }
331 else
332 {
333 $res = Internal\SenderTable::getList(array(
334 'filter' => array(
335 'IS_CONFIRMED' => true,
336 '=EMAIL' => $email,
337 ),
338 'order' => array(
339 'ID' => 'DESC',
340 ),
341 ));
342 $limit = null;
343 while ($item = $res->fetch())
344 {
345 if ($item['OPTIONS']['smtp']['limit'] !== null)
346 {
347 $limit = (int)$item['OPTIONS']['smtp']['limit'];
348 break;
349 }
350 }
351
352 $mailLimit[$email] = $limit;
353
354 $cache->startDataCache();
355 $cache->endDataCache($mailLimit[$email]);
356 }
357 }
358
359 return $mailLimit[$email] < 0 ? 0 : $mailLimit[$email];
360 }
361
373 public static function setEmailLimit(string $email, int $limit, bool $quite = true): bool
374 {
375 $address = new \Bitrix\Main\Mail\Address($email);
376
377 if (!$address->validate())
378 {
379 return false;
380 }
381
382 $email = $address->getEmail();
383
384 $cache = new \CPHPCache();
385 $cache->clean($email, '/main/mail/limit');
386
387 $res = Internal\SenderTable::getList(array(
388 'filter' => array(
389 'IS_CONFIRMED' => true,
390 '=EMAIL' => $email,
391 ),
392 'order' => array(
393 'ID' => 'DESC',
394 ),
395 ));
396
397 if ($limit < 0)
398 {
399 $limit = 0;
400 }
401
402 $hasChanges = false;
403 while ($item = $res->fetch())
404 {
405 $oldLimit = (int)($item['OPTIONS']['smtp']['limit'] ?? 0);
406 if ($item['OPTIONS']['smtp'] && $limit !== $oldLimit)
407 {
408 $item['OPTIONS']['smtp']['limit'] = $limit;
409 $updateResult = Internal\SenderTable::update($item['ID'], ['OPTIONS' => $item['OPTIONS']]);
410 $hasChanges = true;
411 if (!$quite && ($limit < $oldLimit || $oldLimit <= 0) && $updateResult->isSuccess())
412 {
413 $event = new Event('main', self::MAIN_SENDER_SMTP_LIMIT_DECREASE, ['EMAIL'=>$email]);
414 $event->send();
415 }
416 }
417 }
418
419 return $hasChanges;
420 }
421
430 public static function removeEmailLimit(string $email): bool
431 {
432 $address = new \Bitrix\Main\Mail\Address($email);
433
434 if (!$address->validate())
435 {
436 return false;
437 }
438
439 $email = $address->getEmail();
440 $cache = new \CPHPCache();
441 $cache->clean($email, '/main/mail/limit');
442
443 $res = Internal\SenderTable::getList(array(
444 'filter' => array(
445 'IS_CONFIRMED' => true,
446 '=EMAIL' => $email,
447 ),
448 'order' => array(
449 'ID' => 'DESC',
450 ),
451 ));
452
453 while ($item = $res->fetch())
454 {
455 if (isset($item['OPTIONS']['smtp']['limit']))
456 {
457 unset($item['OPTIONS']['smtp']['limit']);
458 Internal\SenderTable::update($item['ID'], ['OPTIONS' => $item['OPTIONS']]);
459 }
460 }
461
462 return true;
463 }
464
465 public static function applyCustomSmtp($event)
466 {
467 $headers = $event->getParameter('arguments')->additional_headers;
468 $context = $event->getParameter('arguments')->context;
469
470 if (empty($context) || !($context instanceof Context))
471 {
472 return;
473 }
474
475 if ($context->getSmtp() && $context->getSmtp()->getHost())
476 {
477 return;
478 }
479
480 if (preg_match('/X-Bitrix-Mail-SMTP-Host:/i', $headers))
481 {
482 return;
483 }
484
485 $eol = Mail::getMailEol();
486 $eolh = preg_replace('/([a-f0-9]{2})/i', '\x\1', bin2hex($eol));
487
488 if (preg_match(sprintf('/(^|%1$s)From:(.+?)(%1$s([^\s]|$)|$)/is', $eolh), $headers, $matches))
489 {
490 $address = new Address(preg_replace(sprintf('/%s\s+/', $eolh), '', $matches[2]));
491 if ($address->validate())
492 {
493 if ($customSmtp = static::getCustomSmtp($address->getEmail()))
494 {
495 $context->setSmtp($customSmtp);
496 }
497 }
498 }
499 }
500
501 public static function prepareUserMailboxes($userId = null)
502 {
503 global $USER;
504
505 static $mailboxes = array();
506
507 if (!($userId > 0))
508 {
509 if (is_object($USER) && $USER->isAuthorized())
510 {
511 $userId = $USER->getId();
512 }
513 }
514
515 if (!($userId > 0))
516 {
517 return array();
518 }
519
520 if (array_key_exists($userId, $mailboxes))
521 {
522 return $mailboxes[$userId];
523 }
524
525 $mailboxes[$userId] = array();
526
527 if (is_object($USER) && $USER->isAuthorized() && $USER->getId() == $userId)
528 {
529 $userData = array(
530 'ID' => $USER->getId(),
531 'TITLE' => $USER->getParam("TITLE"),
532 'NAME' => $USER->getFirstName(),
533 'SECOND_NAME' => $USER->getSecondName(),
534 'LAST_NAME' => $USER->getLastName(),
535 'LOGIN' => $USER->getLogin(),
536 'EMAIL' => $USER->getEmail(),
537 );
538
539 $isAdmin = in_array(1, $USER->getUserGroupArray());
540 }
541 else
542 {
543 $userData = Main\UserTable::getList(array(
544 'select' => array('ID', 'TITLE', 'NAME', 'SECOND_NAME', 'LAST_NAME', 'LOGIN', 'EMAIL'),
545 'filter' => array('=ID' => $userId),
546 ))->fetch();
547
548 $isAdmin = in_array(1, \CUser::getUserGroup($userId));
549 }
550
551 $userNameFormated = \CUser::formatName(\CSite::getNameFormat(), $userData, true, false);
552
553 if (\CModule::includeModule('mail'))
554 {
555 foreach (\Bitrix\Mail\MailboxTable::getUserMailboxes($userId) as $mailbox)
556 {
557 if (!empty($mailbox['EMAIL']))
558 {
559 $mailboxName = trim($mailbox['USERNAME']) ?: trim($mailbox['OPTIONS']['name']) ?: $userNameFormated;
560
561 $key = hash('crc32b', mb_strtolower($mailboxName).$mailbox['EMAIL']);
562 $mailboxes[$userId][$key] = array(
563 'name' => $mailboxName,
564 'email' => $mailbox['EMAIL'],
565 'showEditHint' => true,
566 );
567 }
568 }
569 }
570
571 // @TODO: query
572 $crmAddress = new Address(Main\Config\Option::get('crm', 'mail', ''));
573 if ($crmAddress->validate())
574 {
575 $key = hash('crc32b', mb_strtolower($userNameFormated).$crmAddress->getEmail());
576
577 $mailboxes[$userId][$key] = [
578 'name' => $crmAddress->getName() ?: $userNameFormated,
579 'email' => $crmAddress->getEmail(),
580 ];
581 }
582
583 $res = SenderTable::getList(array(
584 'filter' => array(
585 'IS_CONFIRMED' => true,
586 array(
587 'LOGIC' => 'OR',
588 '=USER_ID' => $userId,
589 'IS_PUBLIC' => true,
590 ),
591 ),
592 'order' => array(
593 'ID' => 'ASC',
594 ),
595 ));
596 while ($item = $res->fetch())
597 {
598 $item['NAME'] = trim($item['NAME']) ?: $userNameFormated;
599 $item['EMAIL'] = mb_strtolower($item['EMAIL']);
600 $key = hash('crc32b', mb_strtolower($item['NAME']).$item['EMAIL']);
601
602 if (!isset($mailboxes[$userId][$key]))
603 {
604 $mailboxes[$userId][$key] = [
605 'id' => $item['ID'],
606 'name' => $item['NAME'],
607 'email' => $item['EMAIL'],
608 'can_delete' => $userId == $item['USER_ID'] || $item['IS_PUBLIC'] && $isAdmin,
609 ];
610 }
611 else if (!isset($mailboxes[$userId][$key]['id']))
612 {
613 $mailboxes[$userId][$key]['id'] = $item['ID'];
614 $mailboxes[$userId][$key]['can_delete'] = $userId == $item['USER_ID'] || $item['IS_PUBLIC'] && $isAdmin;
615 }
616 }
617
618 foreach ($mailboxes[$userId] as $key => $item)
619 {
620 $mailboxes[$userId][$key]['formated'] = sprintf(
621 $item['name'] ? '%s <%s>' : '%s%s',
622 $item['name'], $item['email']
623 );
624
625 $mailboxes[$userId][$key]['userId'] = $userId;
626 }
627
628 $mailboxes[$userId] = array_values($mailboxes[$userId]);
629
630 return $mailboxes[$userId];
631 }
632
633 private static function getOAuthTokenExpireGapSeconds(): int
634 {
635 // we use 55 minutes because providers give tokens for 1 hour or more,
636 // 5 minutes is left for not refresh token too frequent, for mass send
637 $default = isModuleInstalled('bitrix24') ? 55 * 60 : 10;
638
639 return (int)Main\Config\Option::get('main', '~oauth_token_expire_gap_seconds', $default);
640 }
641
642}
static includeModule($moduleName)
Definition loader.php:69
static removeEmailLimit(string $email)
Definition sender.php:430
static checkEmail(&$fields, &$error=null, Main\ErrorCollection &$errors=null)
Definition sender.php:84
static getEmailLimit($email)
Definition sender.php:311
static confirm($ids)
Definition sender.php:110
static getCustomSmtp($email)
Definition sender.php:240
const MAIN_SENDER_SMTP_LIMIT_DECREASE
Definition sender.php:14
static add(array $fields)
Definition sender.php:16
static prepareUserMailboxes($userId=null)
Definition sender.php:501
static clearCustomSmtpCache($email)
Definition sender.php:234
static setEmailLimit(string $email, int $limit, bool $quite=true)
Definition sender.php:373
static applyCustomSmtp($event)
Definition sender.php:465