ILIAS  trunk Revision v12.0_alpha-377-g3641b37b9db
class.ilMail.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
29
30class ilMail
31{
32 use FileDataRCHandling;
33
34 public const string ILIAS_HOST = 'ilias';
35 public const string PROP_CONTEXT_SUBJECT_PREFIX = 'subject_prefix';
36
38 public int $user_id;
39 private string $table_mail;
40 private string $table_mail_saved;
42 protected ?array $mail_data = [];
43 private bool $save_in_sentbox;
44 private bool $append_installation_signature = false;
45 private bool $append_user_signature = false;
46
47 private ?string $context_id = null;
48 private array $context_parameters = [];
49
51 private array $mail_options_by_usr_id_map = [];
52
54 private array $user_instances_by_id_map = [];
56 private readonly Conductor $legal_documents;
58
59 public function __construct(
60 private int $a_user_id,
61 private ?ilMailAddressTypeFactory $mail_address_type_factory = null,
62 private ilMailRfc822AddressParserFactory $mail_address_parser_factory = new ilMailRfc822AddressParserFactory(),
63 private ?ilAppEventHandler $event_handler = null,
64 private ?ilLogger $logger = null,
65 private ?ilDBInterface $db = null,
66 private ?ilLanguage $lng = null,
67 private ?ilFileDataMail $mail_file_data = null,
68 protected ?ilMailOptions $mail_options = null,
69 private ?ilMailbox $mailbox = null,
70 private ?ilMailMimeSenderFactory $sender_factory = null,
71 private ?Closure $usr_id_by_login_callable = null,
72 private ?AutoresponderService $auto_responder_service = null,
73 private ?int $mail_admin_node_ref_id = null,
74 private ?int $mail_obj_ref_id = null,
75 private ?ilObjUser $actor = null,
76 private ?ilMailTemplatePlaceholderResolver $placeholder_resolver = null,
77 private ?ilMailTemplatePlaceholderToEmptyResolver $placeholder_to_empty_resolver = null,
80 ) {
81 global $DIC;
82 $this->logger = $logger ?? ilLoggerFactory::getLogger('mail');
83 $this->mail_address_type_factory = $mail_address_type_factory ?? new ilMailAddressTypeFactory(null, $logger);
84 $this->mail_address_parser_factory = $this->mail_address_parser_factory ?? new ilMailRfc822AddressParserFactory();
85 $this->event_handler = $event_handler ?? $DIC->event();
86 $this->db = $db ?? $DIC->database();
87 $this->lng = $lng ?? $DIC->language();
88 $this->actor = $actor ?? $DIC->user();
89 $this->mail_file_data = $mail_file_data ?? new ilFileDataMail($a_user_id);
90 $this->mail_options = $mail_options ?? new ilMailOptions($a_user_id);
91 $this->mailbox = $mailbox ?? new ilMailbox($a_user_id);
92
93 $this->sender_factory = $sender_factory ?? $DIC->mail()->mime()->senderFactory();
94 $this->usr_id_by_login_callable = $usr_id_by_login_callable ?? (static fn(string $login): int => (int) ilObjUser::_lookupId($login));
95 $this->auto_responder_service = $auto_responder_service ?? $DIC->mail()->autoresponder();
96 $this->user_id = $a_user_id;
97 if ($this->mail_obj_ref_id === null) {
99 }
100 $this->lng->loadLanguageModule('mail');
101 $this->table_mail = 'mail';
102 $this->table_mail_saved = 'mail_saved';
103 $this->setSaveInSentbox(false);
104 $this->placeholder_resolver = $placeholder_resolver ?? $DIC->mail()->placeholderResolver();
105 $this->placeholder_to_empty_resolver = $placeholder_to_empty_resolver ?? $DIC->mail()->placeholderToEmptyResolver();
106 $this->legal_documents = $legal_documents ?? $DIC['legalDocuments'];
107 $this->signature_service = $signature_service ?? $DIC->mail()->signature();
108 $this->refinery = $DIC->refinery();
109 }
110
112 {
113 return $this->auto_responder_service;
114 }
115
116 public function withContextId(string $context_id): self
117 {
118 $clone = clone $this;
119
120 $clone->context_id = $context_id;
121
122 return $clone;
123 }
124
125 public function withContextParameters(array $parameters): self
126 {
127 $clone = clone $this;
128
129 $clone->context_parameters = $parameters;
130
131 return $clone;
132 }
133
134 private function isSystemMail(): bool
135 {
136 return $this->user_id === ANONYMOUS_USER_ID;
137 }
138
139 public function existsRecipient(string $new_recipient, string $existing_recipients): bool
140 {
141 $new_addresses = new ilMailAddressListImpl($this->parseAddresses($new_recipient));
142 $addresses = new ilMailAddressListImpl($this->parseAddresses($existing_recipients));
143 $list = new ilMailDiffAddressList($new_addresses, $addresses);
144
145 $diffed_addresses = $list->value();
146
147 return $diffed_addresses === [];
148 }
149
150 public function setSaveInSentbox(bool $save_in_sentbox): void
151 {
152 $this->save_in_sentbox = $save_in_sentbox;
153 }
154
155 public function getSaveInSentbox(): bool
156 {
158 }
159
160 private function readMailObjectReferenceId(): void
161 {
162 $this->mail_obj_ref_id = ilMailGlobalServices::getMailObjectRefId();
163 }
164
165 public function getMailObjectReferenceId(): int
166 {
167 return $this->mail_obj_ref_id;
168 }
169
170 public function formatNamesForOutput(string $recipients): string
171 {
172 $recipients = trim($recipients);
173 if ($recipients === '') {
174 return $this->lng->txt('not_available');
175 }
176
177 $names = [];
178
179 $recipients = array_filter(array_map('trim', explode(',', $recipients)));
180 foreach ($recipients as $recipient) {
181 $usr_id = ilObjUser::_lookupId($recipient);
182 if (is_int($usr_id) && $usr_id > 0) {
183 $pp = ilObjUser::_lookupPref($usr_id, 'public_profile');
184 if ($pp === 'g' || ($pp === 'y' && !$this->actor->isAnonymous())) {
185 $user = $this->getUserInstanceById($usr_id);
186 if ($user) {
187 $names[] = $user->getFullname() . ' [' . $recipient . ']';
188 continue;
189 }
190 }
191 }
192
193 $names[] = $recipient;
194 }
195
196 return implode(', ', $names);
197 }
198
199 public function getPreviousMail(int $mail_id): ?array
200 {
201 $this->db->setLimit(1, 0);
202
203 $query = implode(' ', [
204 "SELECT b.* FROM $this->table_mail a",
205 "INNER JOIN $this->table_mail b ON b.folder_id = a.folder_id",
206 'AND b.user_id = a.user_id AND b.send_time > a.send_time',
207 'WHERE a.user_id = %s AND a.mail_id = %s ORDER BY b.send_time ASC',
208 ]);
209 $res = $this->db->queryF(
210 $query,
211 ['integer', 'integer'],
212 [$this->user_id, $mail_id]
213 );
214
215 $this->mail_data = $this->fetchMailData($this->db->fetchAssoc($res));
216
217 return $this->mail_data;
218 }
219
220 public function getNextMail(int $mail_id): ?array
221 {
222 $this->db->setLimit(1, 0);
223
224 $query = implode(' ', [
225 "SELECT b.* FROM $this->table_mail a",
226 "INNER JOIN $this->table_mail b ON b.folder_id = a.folder_id",
227 'AND b.user_id = a.user_id AND b.send_time < a.send_time',
228 'WHERE a.user_id = %s AND a.mail_id = %s ORDER BY b.send_time DESC',
229 ]);
230 $res = $this->db->queryF(
231 $query,
232 ['integer', 'integer'],
233 [$this->user_id, $mail_id]
234 );
235
236 $this->mail_data = $this->fetchMailData($this->db->fetchAssoc($res));
237
238 return $this->mail_data;
239 }
240
241 public function getMailsOfFolder(int $a_folder_id, array $filter = []): array
242 {
243 $mails = [];
244
245 $query =
246 'SELECT sender_id, m_subject, mail_id, m_status, send_time, import_name ' .
247 "FROM $this->table_mail " .
248 'LEFT JOIN object_data ON obj_id = sender_id ' .
249 'WHERE user_id = %s AND folder_id = %s ' .
250 'AND ((sender_id > 0 AND sender_id IS NOT NULL AND obj_id IS NOT NULL) ' .
251 'OR (sender_id = 0 OR sender_id IS NULL))';
252
253 if (isset($filter['status']) && $filter['status'] !== '') {
254 $query .= ' AND m_status = ' . $this->db->quote($filter['status'], 'text');
255 }
256
257 $query .= ' ORDER BY send_time DESC';
258
259 $res = $this->db->queryF(
260 $query,
261 ['integer', 'integer'],
262 [$this->user_id, $a_folder_id]
263 );
264
265 while ($row = $this->db->fetchAssoc($res)) {
266 $mails[] = $this->fetchMailData($row);
267 }
268
269 return array_filter($mails);
270 }
271
272 public function countMailsOfFolder(int $folder_id): int
273 {
274 $res = $this->db->queryF(
275 "SELECT COUNT(*) FROM $this->table_mail WHERE user_id = %s AND folder_id = %s",
276 ['integer', 'integer'],
277 [$this->user_id, $folder_id]
278 );
279
280 return $this->db->numRows($res);
281 }
282
283 public function deleteMailsOfFolder(int $folder_id): void
284 {
285 $mails = $this->getMailsOfFolder($folder_id);
286 foreach ($mails as $mail_data) {
287 $this->deleteMails([$mail_data['mail_id']]);
288 }
289 }
290
291 public function getMail(int $mail_id): ?array
292 {
293 $res = $this->db->queryF(
294 "SELECT * FROM $this->table_mail WHERE user_id = %s AND mail_id = %s",
295 ['integer', 'integer'],
296 [$this->user_id, $mail_id]
297 );
298
299 $this->mail_data = $this->fetchMailData($this->db->fetchAssoc($res));
300
301 return $this->mail_data;
302 }
303
307 public function markRead(array $mail_ids): void
308 {
309 $values = [];
310 $types = [];
311
312 $query = "UPDATE $this->table_mail SET m_status = %s WHERE user_id = %s ";
313 $types[] = 'text';
314 $types[] = 'integer';
315 $values[] = 'read';
316 $values[] = $this->user_id;
317
318 if ($mail_ids !== []) {
319 $query .= ' AND ' . $this->db->in('mail_id', $mail_ids, false, 'integer');
320 }
321
322 $this->db->manipulateF($query, $types, $values);
323 }
324
328 public function markUnread(array $mail_ids): void
329 {
330 $values = [];
331 $types = [];
332
333 $query = "UPDATE $this->table_mail SET m_status = %s WHERE user_id = %s ";
334 $types[] = 'text';
335 $types[] = 'integer';
336 $values[] = 'unread';
337 $values[] = $this->user_id;
338
339 if ($mail_ids !== []) {
340 $query .= ' AND ' . $this->db->in('mail_id', $mail_ids, false, 'integer');
341 }
342
343 $this->db->manipulateF($query, $types, $values);
344 }
345
349 public function moveMailsToFolder(array $mail_ids, int $folder_id): bool
350 {
351 $values = [];
352 $types = [];
353
354 $mail_ids = array_filter(array_map(intval(...), $mail_ids));
355
356 if ([] === $mail_ids) {
357 return false;
358 }
359
360 $query =
361 "UPDATE $this->table_mail " .
362 'INNER JOIN mail_obj_data ' .
363 'ON mail_obj_data.obj_id = %s AND mail_obj_data.user_id = %s ' .
364 "SET $this->table_mail.folder_id = mail_obj_data.obj_id " .
365 "WHERE $this->table_mail.user_id = %s";
366 $types[] = 'integer';
367 $types[] = 'integer';
368 $types[] = 'integer';
369 $values[] = $folder_id;
370 $values[] = $this->user_id;
371 $values[] = $this->user_id;
372
373 $query .= ' AND ' . $this->db->in('mail_id', $mail_ids, false, 'integer');
374
375 $affected_rows = $this->db->manipulateF($query, $types, $values);
376
377 return $affected_rows > 0;
378 }
379
383 public function deleteMails(array $mail_ids): void
384 {
385 $mail_ids = array_filter(array_map('intval', $mail_ids));
386 foreach ($mail_ids as $id) {
387 $this->db->manipulateF(
388 "DELETE FROM $this->table_mail WHERE user_id = %s AND mail_id = %s",
389 ['integer', 'integer'],
390 [$this->user_id, $id]
391 );
392 $this->mail_file_data->deassignAttachmentFromDirectory($id);
393 }
394 }
395
396 public function fetchMailData(?array $row): ?array
397 {
398 if (!is_array($row) || empty($row)) {
399 return null;
400 }
401
402 if (isset($row['attachments']) && is_string($row['attachments']) && str_contains($row['attachments'], '{')) {
403 $row['attachments'] = unserialize($row['attachments']);
404 } elseif (isset($row['attachments']) && is_string($row['attachments']) && $row['attachments'] !== '') {
405 $row['attachments'] = new ResourceCollectionIdentification($row['attachments']);
406 } else {
407 $row['attachments'] = null;
408 }
409
410 if (isset($row['tpl_ctx_params']) && is_string($row['tpl_ctx_params'])) {
411 $decoded = json_decode($row['tpl_ctx_params'], true, 512, JSON_THROW_ON_ERROR);
412 $row['tpl_ctx_params'] = (array) ($decoded ?? []);
413 } else {
414 $row['tpl_ctx_params'] = [];
415 }
416
417 if (isset($row['mail_id'])) {
418 $row['mail_id'] = (int) $row['mail_id'];
419 }
420
421 if (isset($row['user_id'])) {
422 $row['user_id'] = (int) $row['user_id'];
423 }
424
425 if (isset($row['folder_id'])) {
426 $row['folder_id'] = (int) $row['folder_id'];
427 }
428
429 if (isset($row['sender_id'])) {
430 $row['sender_id'] = (int) $row['sender_id'];
431 }
432
433 if (isset($row['use_placeholders'])) {
434 $row['use_placeholders'] = (bool) $row['use_placeholders'];
435 }
436
437 $null_to_string_properties = ['m_subject', 'm_message', 'rcp_to', 'rcp_cc', 'rcp_bcc'];
438 foreach ($null_to_string_properties as $null_to_string_property) {
439 if (!isset($row[$null_to_string_property])) {
440 $row[$null_to_string_property] = '';
441 }
442 }
443
444 return $row;
445 }
446
447 public function getNewDraftId(int $folder_id): int
448 {
449 $next_id = $this->db->nextId($this->table_mail);
450 $this->db->insert($this->table_mail, [
451 'mail_id' => ['integer', $next_id],
452 'user_id' => ['integer', $this->user_id],
453 'folder_id' => ['integer', $folder_id],
454 'sender_id' => ['integer', $this->user_id],
455 ]);
456
457 return $next_id;
458 }
459
463 public function updateDraft(
464 int $a_folder_id,
465 array $a_attachments,
466 string $a_rcp_to,
467 string $a_rcp_cc,
468 string $a_rcp_bcc,
469 string $a_m_subject,
470 string $a_m_message,
471 int $a_draft_id = 0,
472 ?DateTimeImmutable $schedule_time = null,
473 bool $a_use_placeholders = false,
474 ?string $a_tpl_context_id = null,
475 array $a_tpl_context_params = []
476 ): int {
477 $this->db->update(
478 $this->table_mail,
479 [
480 'folder_id' => ['integer', $a_folder_id],
481 'attachments' => ['clob', serialize($a_attachments)],
482 'send_time' => ['timestamp', date('Y-m-d H:i:s')],
483 'rcp_to' => ['clob', $a_rcp_to],
484 'rcp_cc' => ['clob', $a_rcp_cc],
485 'rcp_bcc' => ['clob', $a_rcp_bcc],
486 'm_status' => ['text', 'read'],
487 'm_subject' => ['text', $a_m_subject],
488 'm_message' => ['clob', $a_m_message],
489 'use_placeholders' => ['integer', (int) $a_use_placeholders],
490 'tpl_ctx_id' => ['text', $a_tpl_context_id],
491 'tpl_ctx_params' => ['blob', json_encode($a_tpl_context_params, JSON_THROW_ON_ERROR)],
492 'schedule_datetime' => [ilDBConstants::T_TIMESTAMP, $schedule_time?->format('Y-m-d H:i:s')],
493 'schedule_timezone' => [ilDBConstants::T_TEXT, $schedule_time?->getTimezone()->getName()],
494 ],
495 [
496 'mail_id' => ['integer', $a_draft_id],
497 ]
498 );
499
500 return $a_draft_id;
501 }
502
506 public function scheduledMail(
507 int $folder_id,
508 int $sender_usr_id,
509 MailScheduleData $mail_data,
510 ?string $template_context_id = null,
511 array $template_context_parameters = []
512 ): int {
513 $message = $mail_data->getMailDeliveryData()->getMessage();
514 if ($mail_data->getMailDeliveryData()->isUsePlaceholder()) {
515 $message = $this->replacePlaceholders($mail_data->getMailDeliveryData()->getMessage(), $sender_usr_id);
516 }
517 $message = str_ireplace(['<br />', '<br>', '<br/>'], "\n", $message);
518 $mail_values = [
519 'user_id' => [ilDBConstants::T_INTEGER, $sender_usr_id],
520 'folder_id' => [ilDBConstants::T_INTEGER, $folder_id],
521 'sender_id' => [ilDBConstants::T_INTEGER, $sender_usr_id],
522 'attachments' => [ilDBConstants::T_CLOB, serialize($mail_data->getMailDeliveryData()->getAttachments())],
523 'send_time' => [ilDBConstants::T_TIMESTAMP, date('Y-m-d H:i:s')],
524 'rcp_to' => [ilDBConstants::T_CLOB, $mail_data->getMailDeliveryData()->getTo()],
525 'rcp_cc' => [ilDBConstants::T_CLOB, $mail_data->getMailDeliveryData()->getCC()],
526 'rcp_bcc' => [ilDBConstants::T_CLOB, $mail_data->getMailDeliveryData()->getBcc()],
527 'm_status' => [ilDBConstants::T_TEXT, 'read'],
528 'm_subject' => [ilDBConstants::T_TEXT, $mail_data->getMailDeliveryData()->getSubject()],
529 'm_message' => [ilDBConstants::T_CLOB, $message],
530 'tpl_ctx_id' => [ilDBConstants::T_TEXT, $template_context_id],
531 'tpl_ctx_params' => [ilDBConstants::T_BLOB, json_encode($template_context_parameters, JSON_THROW_ON_ERROR)],
532 'schedule_datetime' => [ilDBConstants::T_TIMESTAMP, $mail_data->getScheduleDatetime()->format('Y-m-d H:i:s')],
533 'schedule_timezone' => [ilDBConstants::T_TEXT, $mail_data->getScheduleDatetime()->getTimezone()->getName()],
534 ];
535
536 if (!$mail_data->getMailDeliveryData()->getInternalMailId()) {
537 $outbox_id = $this->db->nextId($this->table_mail);
538 $mail_values['mail_id'] = [ilDBConstants::T_INTEGER, $outbox_id];
539 $this->db->insert($this->table_mail, $mail_values);
540 } else {
541 $outbox_id = $mail_data->getMailDeliveryData()->getInternalMailId();
542 $this->db->update($this->table_mail, $mail_values, [
543 'mail_id' => [ilDBConstants::T_INTEGER, $outbox_id],
544 ]);
545 }
546
547 return $outbox_id;
548 }
549
550 private function sendInternalMail(
551 int $folder_id,
552 int $sender_usr_id,
553 array $attachments,
554 string $to,
555 string $cc,
556 string $bcc,
557 string $status,
558 string $subject,
559 string $message,
560 int $usr_id = 0,
561 bool $use_placeholders = false,
562 ?string $template_contenxt_id = null,
563 array $template_context_parameters = []
564 ): int {
565 $usr_id = $usr_id ?: $this->user_id;
566
567 if ($use_placeholders) {
568 $message = $this->replacePlaceholders($message, $usr_id);
569 }
570 $message = $this->formatLinebreakMessage($this->refinery->string()->markdown()->toHTML()->transform($message) ?? '');
571
572 $next_id = $this->db->nextId($this->table_mail);
573 $this->db->insert($this->table_mail, [
574 'mail_id' => ['integer', $next_id],
575 'user_id' => ['integer', $usr_id],
576 'folder_id' => ['integer', $folder_id],
577 'sender_id' => ['integer', $sender_usr_id],
578 'attachments' => ['clob', serialize($attachments)],
579 'send_time' => ['timestamp', date('Y-m-d H:i:s')],
580 'rcp_to' => ['clob', $to],
581 'rcp_cc' => ['clob', $cc],
582 'rcp_bcc' => ['clob', $bcc],
583 'm_status' => ['text', $status],
584 'm_subject' => ['text', $subject],
585 'm_message' => ['clob', $message],
586 'tpl_ctx_id' => ['text', $template_contenxt_id],
587 'tpl_ctx_params' => ['blob', json_encode($template_context_parameters, JSON_THROW_ON_ERROR)],
588 ]);
589
590 $sender_equals_reveiver = $usr_id === $this->mailbox->getUsrId();
591 $is_sent_folder_of_sender = false;
592 if ($sender_equals_reveiver) {
593 $current_folder_id = $this->getSubjectSentFolderId();
594 $is_sent_folder_of_sender = $folder_id === $current_folder_id;
595 }
596
597 $raise_event = !$sender_equals_reveiver || !$is_sent_folder_of_sender;
598
599 if ($raise_event) {
600 $this->event_handler->raise('components/ILIAS/Mail', 'sentInternalMail', [
601 'id' => $next_id,
602 'subject' => $subject,
603 'body' => $message,
604 'from_usr_id' => $sender_usr_id,
605 'to_usr_id' => $usr_id,
606 'rcp_to' => $to,
607 'rcp_cc' => $cc,
608 'rcp_bcc' => $bcc,
609 ]);
610 }
611
612 return $next_id;
613 }
614
615 private function replacePlaceholders(
616 string $message,
617 int $usr_id = 0
618 ): string {
619 try {
620 if ($this->context_id) {
622 } else {
624 }
625
626 $user = $usr_id > 0 ? $this->getUserInstanceById($usr_id) : null;
627 $message = $this->placeholder_resolver->resolve(
628 $context,
629 $message,
630 $user,
631 $this->context_parameters
632 );
633 } catch (Exception $e) {
634 $this->logger->error(sprintf(
635 '%s has been called with invalid context: %s / %s',
636 __METHOD__,
637 $e->getMessage(),
638 $e->getTraceAsString()
639 ));
640 }
641
642 return $message;
643 }
644
645 private function replacePlaceholdersEmpty(string $message): string
646 {
647 return $this->placeholder_to_empty_resolver->resolve($message);
648 }
649
650 private function distributeMail(MailDeliveryData $mail_data): bool
651 {
652 $this->auto_responder_service->emptyAutoresponderData();
653 $to_usr_ids = $this->getUserIds([$mail_data->getTo()]);
654 $this->logger->debug(sprintf(
655 'Parsed TO user ids from given recipients for serial letter notification: %s',
656 implode(', ', $to_usr_ids)
657 ));
658
659 $other_usr_ids = $this->getUserIds([$mail_data->getCc(), $mail_data->getBcc()]);
660 $cc_bcc_recipients = array_map(
661 $this->createRecipient(...),
662 $other_usr_ids
663 );
664 $this->logger->debug(sprintf(
665 'Parsed CC/BCC user ids from given recipients for serial letter notification: %s',
666 implode(', ', $other_usr_ids)
667 ));
668
669 if ($mail_data->isUsePlaceholder()) {
670 $this->sendMailWithReplacedPlaceholder($mail_data, $to_usr_ids);
671 $this->sendMailWithReplacedEmptyPlaceholder($mail_data, $cc_bcc_recipients);
672 } else {
673 $this->sendMailWithoutReplacedPlaceholder($mail_data, $to_usr_ids, $cc_bcc_recipients);
674 }
675
676 $this->auto_responder_service->disableAutoresponder();
677 $this->auto_responder_service->handleAutoresponderMails($this->user_id);
678
679 return true;
680 }
681
686 MailDeliveryData $mail_data,
687 array $to_usr_ids
688 ): void {
689 foreach ($to_usr_ids as $user_id) {
690 $recipient = $this->createRecipient($user_id);
691
692 $this->sendChanneledMails(
693 $mail_data,
694 [$recipient],
695 $this->replacePlaceholders($mail_data->getMessage(), $user_id),
696 );
697 }
698 }
699
704 MailDeliveryData $mail_data,
705 array $recipients,
706 ): void {
707 $this->sendChanneledMails(
708 $mail_data,
709 $recipients,
710 $this->replacePlaceholdersEmpty($mail_data->getMessage()),
711 );
712 }
713
719 MailDeliveryData $mail_data,
720 array $to_usr_ids,
721 array $cc_bcc_recipients
722 ): void {
723 $to_recipients = array_map(
724 $this->createRecipient(...),
725 $to_usr_ids
726 );
727
728 $this->sendChanneledMails(
729 $mail_data,
730 array_merge($to_recipients, $cc_bcc_recipients),
731 $mail_data->getMessage()
732 );
733 }
734
738 private function sendChanneledMails(
739 MailDeliveryData $mail_data,
740 array $recipients,
741 string $message
742 ): void {
743 $usr_id_to_external_email_addresses_map = [];
744
745 foreach ($recipients as $recipient) {
746 if (!$recipient->isUser()) {
747 $this->logger->critical(sprintf(
748 'Skipped recipient with id %s (User not found)',
749 $recipient->getUserId()
750 ));
751 continue;
752 }
753
754 $can_read_internal = $recipient->evaluateInternalMailReadability();
755 if ($this->isSystemMail() && !$can_read_internal->isOk()) {
756 $this->logger->debug(sprintf(
757 'Skipped recipient with id %s and reason: %s',
758 $recipient->getUserId(),
759 is_string($can_read_internal->error()) ? $can_read_internal->error() : $can_read_internal->error()->getMessage()
760 ));
761 continue;
762 }
763
764 if ($recipient->isUserActive() && !$recipient->isUserExpired()) {
765 if (!$can_read_internal->isOk() || $recipient->userWantsToReceiveExternalMails()) {
766 $email_addresses = $recipient->getExternalMailAddress();
767 $usr_id_to_external_email_addresses_map[$recipient->getUserId()] = $email_addresses;
768
769 if ($recipient->onlyToExternalMailAddress()) {
770 $this->logger->debug(sprintf(
771 'Recipient with id %s will only receive external emails sent to: %s',
772 $recipient->getUserId(),
773 implode(', ', $email_addresses)
774 ));
775 continue;
776 }
777
778 $this->logger->debug(sprintf(
779 'Recipient with id %s will additionally receive external emails ' .
780 '(because the user wants to receive it externally, or the user cannot did not accept ' .
781 'the legal documents) sent to: %s',
782 $recipient->getUserId(),
783 implode(', ', $email_addresses)
784 ));
785 } else {
786 $this->logger->debug(sprintf(
787 'Recipient with id %s does not want to receive external emails',
788 $recipient->getUserId()
789 ));
790 }
791 } else {
792 $this->logger->debug(sprintf(
793 'Recipient with id %s is inactive or expired and will not receive external emails',
794 $recipient->getUserId()
795 ));
796 }
797
798 $mbox = clone $this->mailbox;
799 $mbox->setUsrId($recipient->getUserId());
800 $recipient_inbox_id = $mbox->getInboxFolder();
801
802 $internal_mail_id = $this->sendInternalMail(
803 $recipient_inbox_id,
804 $this->user_id,
805 $mail_data->getAttachments(),
806 $mail_data->getTo(),
807 $mail_data->getCc(),
808 '',
809 'unread',
810 $mail_data->getSubject(),
811 $message,
812 $recipient->getUserId()
813 );
814
815 $this->auto_responder_service->enqueueAutoresponderIfEnabled(
816 $recipient->getUserId(),
817 $recipient->getMailOptions(),
818 $this->getMailOptionsByUserId($this->user_id),
819 );
820
821 if ($mail_data->getAttachments() !== []) {
822 $this->mail_file_data->assignAttachmentsToDirectory($internal_mail_id, $mail_data->getInternalMailId());
823 }
824 }
825
826 $this->delegateExternalEmails(
827 $mail_data->getSubject(),
828 $mail_data->getAttachments(),
829 $message,
830 $usr_id_to_external_email_addresses_map
831 );
832 }
833
838 private function delegateExternalEmails(
839 string $subject,
840 array $attachments,
841 string $message,
842 array $usr_id_to_external_email_addresses_map
843 ): void {
844 if (count($usr_id_to_external_email_addresses_map) === 1) {
845 $usr_id_to_external_email_addresses_map = array_values($usr_id_to_external_email_addresses_map);
846 $first_addresses = current($usr_id_to_external_email_addresses_map);
847
848 $this->sendMimeMail(
849 implode(',', $first_addresses),
850 '',
851 '',
852 $subject,
853 $message,
854 $attachments
855 );
856 } elseif (count($usr_id_to_external_email_addresses_map) > 1) {
857 $flattened_email_addresses = iterator_to_array(new RecursiveIteratorIterator(new RecursiveArrayIterator(
858 $usr_id_to_external_email_addresses_map
859 )), false);
860
861 $flattened_email_addresses = array_unique($flattened_email_addresses);
862
863 // https://mantis.ilias.de/view.php?id=23981 and https://www.ietf.org/rfc/rfc2822.txt
864 $remaining_addresses = '';
865 foreach ($flattened_email_addresses as $email_address) {
866 $sep = '';
867 if ($remaining_addresses !== '') {
868 $sep = ',';
869 }
870
871 $recipients_line_length = ilStr::strLen($remaining_addresses) +
872 ilStr::strLen($sep . $email_address);
873 if ($recipients_line_length >= $this->max_recipient_character_length) {
874 $this->sendMimeMail(
875 '',
876 '',
877 $remaining_addresses,
878 $subject,
879 $message,
880 $attachments
881 );
882
883 $remaining_addresses = '';
884 $sep = '';
885 }
886
887 $remaining_addresses .= ($sep . $email_address);
888 }
889
890 if ($remaining_addresses !== '') {
891 $this->sendMimeMail(
892 '',
893 '',
894 $remaining_addresses,
895 $subject,
896 $message,
897 $attachments
898 );
899 }
900 }
901 }
902
907 private function getUserIds(array $recipients): array
908 {
909 $parsed_usr_ids = [];
910
911 $joined_recipients = implode(',', array_filter(array_map('trim', $recipients)));
912
913 $addresses = $this->parseAddresses($joined_recipients);
914 foreach ($addresses as $address) {
915 $address_type = $this->mail_address_type_factory->getByPrefix($address);
916 $parsed_usr_ids[] = $address_type->resolve();
917 }
918
919 return array_unique(array_merge(...$parsed_usr_ids));
920 }
921
925 private function checkMail(string $to, string $cc, string $bcc, string $subject): array
926 {
927 $errors = [];
928
929 $checks = [
930 $subject => 'mail_add_subject',
931 $to => 'mail_add_recipient',
932 ];
933 foreach ($checks as $string => $error) {
934 if ($string === '') {
935 $errors[] = new ilMailError($error);
936 }
937 }
938
939 if (ilStr::strLen($subject) > 255) {
940 // https://mantis.ilias.de/view.php?id=37881
941 $errors[] = new ilMailError('mail_subject_too_long');
942 }
943
944 return $errors;
945 }
946
950 private function checkRecipients(string $recipients): array
951 {
952 $errors = [];
953
954 try {
955 $addresses = $this->parseAddresses($recipients);
956 foreach ($addresses as $address) {
957 $address_type = $this->mail_address_type_factory->getByPrefix($address);
958 if (!$address_type->validate($this->user_id)) {
959 $errors[] = $address_type->getErrors();
960 }
961 }
962 } catch (Exception $e) {
963 $position = strpos($e->getMessage(), ':');
964 throw new ilMailException(
965 ($position === false) ? $e->getMessage() : substr($e->getMessage(), $position + 2),
966 $e->getCode(),
967 $e
968 );
969 }
970
971 return array_merge(...$errors);
972 }
973
977 public function persistToStage(
978 int $a_user_id,
979 string $a_rcp_to,
980 string $a_rcp_cc,
981 string $a_rcp_bcc,
982 string $a_m_subject,
983 string $a_m_message,
984 ?\ILIAS\ResourceStorage\Identification\ResourceCollectionIdentification $a_attachments = null,
985 bool $a_use_placeholders = false,
986 ?string $a_tpl_context_id = null,
987 ?array $a_tpl_ctx_params = []
988 ): bool {
989 if (!is_null($a_attachments)) {
990 $a_attachments = $a_attachments->serialize();
991 }
992 $this->db->replace(
993 $this->table_mail_saved,
994 [
995 'user_id' => ['integer', $this->user_id],
996 ],
997 [
998 'attachments' => ['text', $a_attachments],
999 'rcp_to' => ['clob', $a_rcp_to],
1000 'rcp_cc' => ['clob', $a_rcp_cc],
1001 'rcp_bcc' => ['clob', $a_rcp_bcc],
1002 'm_subject' => ['text', $a_m_subject],
1003 'm_message' => ['clob', $a_m_message],
1004 'use_placeholders' => ['integer', (int) $a_use_placeholders],
1005 'tpl_ctx_id' => ['text', $a_tpl_context_id],
1006 'tpl_ctx_params' => ['blob', json_encode((array) $a_tpl_ctx_params, JSON_THROW_ON_ERROR)],
1007 ]
1008 );
1009
1010 $this->retrieveFromStage();
1011
1012 return true;
1013 }
1014
1015 public function retrieveFromStage(): array
1016 {
1017 $res = $this->db->queryF(
1018 "SELECT * FROM $this->table_mail_saved WHERE user_id = %s",
1019 ['integer'],
1020 [$this->user_id]
1021 );
1022
1023 $this->mail_data = $this->fetchMailData($this->db->fetchAssoc($res));
1024 if (!is_array($this->mail_data)) {
1025 $this->persistToStage($this->user_id, '', '', '', '', '', null, false);
1026 }
1027
1028 return $this->mail_data;
1029 }
1030
1036 public function enqueue(
1037 string $a_rcp_to,
1038 string $a_rcp_cc,
1039 string $a_rcp_bcc,
1040 string $a_m_subject,
1041 string $a_m_message,
1042 array $a_attachment,
1043 bool $a_use_placeholders = false
1044 ): array {
1045 global $DIC;
1046
1047 $sanitizeMb4Encoding = new Utf8Mb4Sanitizer();
1048 $a_m_subject = $sanitizeMb4Encoding->transform($a_m_subject);
1049 $a_m_message = $sanitizeMb4Encoding->transform($a_m_message);
1050
1051 $this->logger->info(
1052 'New mail system task:' .
1053 ' To: ' . $a_rcp_to .
1054 ' | CC: ' . $a_rcp_cc .
1055 ' | BCC: ' . $a_rcp_bcc .
1056 ' | Subject: ' . $a_m_subject .
1057 ' | Attachments: ' . print_r($a_attachment, true)
1058 );
1059
1060 if ($a_attachment && !$this->mail_file_data->checkFilesExist($a_attachment)) {
1061 return [new ilMailError('mail_attachment_file_not_exist', [implode(', ', $a_attachment)])];
1062 }
1063
1064 $errors = $this->checkMail($a_rcp_to, $a_rcp_cc, $a_rcp_bcc, $a_m_subject);
1065 if ($errors !== []) {
1066 return $errors;
1067 }
1068
1069 $errors = $this->validateRecipients($a_rcp_to, $a_rcp_cc, $a_rcp_bcc);
1070 if ($errors !== []) {
1071 return $errors;
1072 }
1073
1074 $rcp_to = $a_rcp_to;
1075 $rcp_cc = $a_rcp_cc;
1076 $rcp_bcc = $a_rcp_bcc;
1077
1078 $number_of_external_addresses = $this->getCountRecipients($rcp_to, $rcp_cc, $rcp_bcc);
1079 if (
1080 $number_of_external_addresses > 0 &&
1081 !$this->isSystemMail() &&
1082 !$DIC->rbac()->system()->checkAccessOfUser($this->user_id, 'smtp_mail', $this->mail_obj_ref_id)
1083 ) {
1084 return [new ilMailError('mail_no_permissions_write_smtp')];
1085 }
1086
1087 if ($this->appendInstallationSignature()) {
1088 $a_m_message .= self::_getInstallationSignature();
1089 }
1090
1092 $mail_data = new MailDeliveryData(
1093 $rcp_to,
1094 $rcp_cc,
1095 $rcp_bcc,
1096 $a_m_subject,
1097 $a_m_message,
1098 $a_attachment,
1099 $a_use_placeholders
1100 );
1101 return $this->sendMail($mail_data);
1102 }
1103
1104 $task_factory = $DIC->backgroundTasks()->taskFactory();
1105 $task_manager = $DIC->backgroundTasks()->taskManager();
1106
1107 $bucket = new BasicBucket();
1108 $bucket->setUserId($this->user_id);
1109
1110 $task = $task_factory->createTask(ilMailDeliveryJob::class, [
1111 $this->user_id,
1112 $rcp_to,
1113 $rcp_cc,
1114 $rcp_bcc,
1115 $a_m_subject,
1116 $a_m_message,
1117 serialize($a_attachment),
1118 $a_use_placeholders,
1119 $this->getSaveInSentbox(),
1120 (string) $this->context_id,
1121 serialize(array_merge(
1122 $this->context_parameters,
1123 [
1124 'auto_responder' => $this->auto_responder_service->isAutoresponderEnabled()
1125 ]
1126 ))
1127 ]);
1128 $interaction = $task_factory->createTask(ilMailDeliveryJobUserInteraction::class, [
1129 $task,
1130 $this->user_id,
1131 ]);
1132
1133 $bucket->setTask($interaction);
1134 $bucket->setTitle($this->lng->txt('mail_bg_task_title'));
1135 $bucket->setDescription(sprintf($this->lng->txt('mail_bg_task_desc'), $a_m_subject));
1136
1137 $this->logger->info('Delegated delivery to background task');
1138 $task_manager->run($bucket);
1139
1140 return [];
1141 }
1142
1151 public function sendMail(
1152 MailDeliveryData $mail_data
1153 ): array {
1154 $internal_message_id = $this->saveInSentbox(
1155 $mail_data->getAttachments(),
1156 $mail_data->getTo(),
1157 $mail_data->getCc(),
1158 $mail_data->getBcc(),
1159 $mail_data->getSubject(),
1160 $mail_data->getMessage()
1161 );
1162 $mail_data = $mail_data->withInternalMailId($internal_message_id);
1163
1164 if ($mail_data->getAttachments() !== []) {
1165 $this->mail_file_data->assignAttachmentsToDirectory($internal_message_id, $internal_message_id);
1166 $this->mail_file_data->saveFiles($internal_message_id, $mail_data->getAttachments());
1167 }
1168
1169 $num_external_email_addresses = $this->getCountRecipients(
1170 $mail_data->getTo(),
1171 $mail_data->getCc(),
1172 $mail_data->getBcc()
1173 );
1174
1175 if ($num_external_email_addresses > 0) {
1176 $external_mail_recipients_to = $this->getEmailRecipients($mail_data->getTo());
1177 $external_mail_recipients_cc = $this->getEmailRecipients($mail_data->getCc());
1178 $external_eail_recipients_bcc = $this->getEmailRecipients($mail_data->getBcc());
1179
1180 $this->logger->debug(
1181 'Parsed external email addresses from given recipients /' .
1182 ' To: ' . $external_mail_recipients_to .
1183 ' | CC: ' . $external_mail_recipients_cc .
1184 ' | BCC: ' . $external_eail_recipients_bcc .
1185 ' | Subject: ' . $mail_data->getSubject()
1186 );
1187
1188 $this->sendMimeMail(
1189 $external_mail_recipients_to,
1190 $external_mail_recipients_cc,
1191 $external_eail_recipients_bcc,
1192 $mail_data->getSubject(),
1193 $mail_data->isUsePlaceholder() ?
1194 $this->replacePlaceholders($mail_data->getMessage(), 0) :
1195 $mail_data->getMessage(),
1196 $mail_data->getAttachments()
1197 );
1198 } else {
1199 $this->logger->debug('No external email addresses given in recipient string');
1200 }
1201
1202 $errors = [];
1203 if (!$this->distributeMail($mail_data)) {
1204 $errors['mail_send_error'] = new ilMailError('mail_send_error');
1205 }
1206
1207 if (!$this->getSaveInSentbox()) {
1208 $this->deleteMails([$internal_message_id]);
1209 }
1210
1211 if ($this->isSystemMail()) {
1212 $random = new Random\Randomizer();
1213 if ($random->getInt(0, 50) === 2) {
1215 $this->logger,
1216 $this->mail_file_data
1217 ))->run();
1218 }
1219 }
1220
1221 return array_values($errors);
1222 }
1223
1227 public function validateRecipients(string $to, string $cc, string $bcc): array
1228 {
1229 try {
1230 $errors = [];
1231 $errors = array_merge($errors, $this->checkRecipients($to));
1232 $errors = array_merge($errors, $this->checkRecipients($cc));
1233 $errors = array_merge($errors, $this->checkRecipients($bcc));
1234
1235 if ($errors !== []) {
1236 return array_merge([new ilMailError('mail_following_rcp_not_valid')], $errors);
1237 }
1238 } catch (ilMailException $e) {
1239 return [new ilMailError('mail_generic_rcp_error', [$e->getMessage()])];
1240 }
1241
1242 return [];
1243 }
1244
1245 private function getSubjectSentFolderId(): int
1246 {
1247 $send_folder_id = 0;
1248 if (!$this->isSystemMail()) {
1249 $send_folder_id = $this->mailbox->getSentFolder();
1250 }
1251
1252 return $send_folder_id;
1253 }
1254
1258 private function saveInSentbox(
1259 array $attachment,
1260 string $to,
1261 string $cc,
1262 string $bcc,
1263 string $subject,
1264 string $message
1265 ): int {
1266 return $this->sendInternalMail(
1267 $this->getSubjectSentFolderId(),
1268 $this->user_id,
1269 $attachment,
1270 $to,
1271 $cc,
1272 $bcc,
1273 'read',
1274 $subject,
1275 $message,
1276 $this->user_id
1277 );
1278 }
1279
1283 private function sendMimeMail(
1284 string $to,
1285 string $cc,
1286 string $bcc,
1287 string $subject,
1288 string $message,
1289 array $attachments
1290 ): void {
1291 $mailer = new ilMimeMail();
1292 $mailer->From($this->sender_factory->getSenderByUsrId($this->user_id));
1293 $mailer->To($to);
1294 $mailer->Subject(
1295 $subject,
1296 true,
1297 (string) ($this->context_parameters[self::PROP_CONTEXT_SUBJECT_PREFIX] ?? '')
1298 );
1299
1300 if (!$this->isSystemMail()) {
1301 $message .= $this->signature_service->user($this->user_id);
1302 }
1303 $mailer->Body($this->refinery->string()->markdown()->toHTML()->transform($message) ?? '');
1304
1305 if ($cc !== '') {
1306 $mailer->Cc($cc);
1307 }
1308
1309 if ($bcc !== '') {
1310 $mailer->Bcc($bcc);
1311 }
1312
1313 foreach ($attachments as $attachment) {
1314 $mailer->Attach(
1315 $this->mail_file_data->getAbsoluteAttachmentPoolPathByFilename($attachment),
1316 '',
1317 'inline',
1318 $attachment
1319 );
1320 }
1321
1322 $mailer->Send();
1323 }
1324
1325 public function saveAttachments(?ResourceCollectionIdentification $attachments): void
1326 {
1327 if (!is_null($attachments)) {
1328 $attachments = $attachments->serialize();
1329 }
1330
1331 $this->db->update(
1332 $this->table_mail_saved,
1333 [
1334 'attachments' => ['text', $attachments],
1335 ],
1336 [
1337 'user_id' => ['integer', $this->user_id],
1338 ]
1339 );
1340 }
1341
1346 private function parseAddresses(string $addresses): array
1347 {
1348 if ($addresses !== '') {
1349 $this->logger->debug(sprintf(
1350 'Started parsing of recipient string: %s',
1351 $addresses
1352 ));
1353 }
1354
1355 $parser = $this->mail_address_parser_factory->getParser($addresses);
1356 $parsed_addresses = $parser->parse();
1357
1358 if ($addresses !== '') {
1359 $this->logger->debug(sprintf(
1360 'Parsed addresses: %s',
1361 implode(',', array_map(static fn(ilMailAddress $address): string => (string) $address, $parsed_addresses))
1362 ));
1363 }
1364
1365 return $parsed_addresses;
1366 }
1367
1368 private function getCountRecipient(string $recipients, bool $only_external_addresses = true): int
1369 {
1370 $addresses = new ilMailAddressListImpl($this->parseAddresses($recipients));
1371 if ($only_external_addresses) {
1372 $addresses = new ilMailOnlyExternalAddressList(
1373 $addresses,
1374 self::ILIAS_HOST,
1375 $this->usr_id_by_login_callable
1376 );
1377 }
1378
1379 return count($addresses->value());
1380 }
1381
1382 private function getCountRecipients(
1383 string $to_recipients,
1384 string $cc_recipients,
1385 string $bcc_recipients,
1386 bool $only_external_addresses = true
1387 ): int {
1388 return (
1389 $this->getCountRecipient($to_recipients, $only_external_addresses) +
1390 $this->getCountRecipient($cc_recipients, $only_external_addresses) +
1391 $this->getCountRecipient($bcc_recipients, $only_external_addresses)
1392 );
1393 }
1394
1395 private function getEmailRecipients(string $recipients): string
1396 {
1397 $addresses = new ilMailOnlyExternalAddressList(
1398 new ilMailAddressListImpl($this->parseAddresses($recipients)),
1399 self::ILIAS_HOST,
1400 $this->usr_id_by_login_callable
1401 );
1402
1403 $email_recipients = array_map(static fn(ilMailAddress $address): string => (string) $address, $addresses->value());
1404
1405 return implode(',', $email_recipients);
1406 }
1407
1408 public static function _getAutoGeneratedMessageString(?ilLanguage $lang = null): string
1409 {
1410 global $DIC;
1411
1412 if (!($lang instanceof ilLanguage)) {
1414 }
1415
1416 $lang->loadLanguageModule('mail');
1417
1418 return sprintf(
1419 $lang->txt('mail_auto_generated_info'),
1420 $DIC->settings()->get('inst_name', 'ILIAS ' . ((int) ILIAS_VERSION_NUMERIC)),
1422 ) . "\n\n";
1423 }
1424
1425 public static function _getIliasMailerName(): string
1426 {
1427 global $DIC;
1428 $sender_factory = $DIC->mail()->mime()->senderFactory();
1429
1430 return $sender_factory->system()->getFromName();
1431 }
1432
1436 public function appendInstallationSignature(?bool $a_flag = null)
1437 {
1438 if ($a_flag === null) {
1439 return $this->append_installation_signature;
1440 }
1441
1442 $this->append_installation_signature = $a_flag;
1443 return $this;
1444 }
1445
1446 public static function _getInstallationSignature(): string
1447 {
1448 global $DIC;
1449 return $DIC->mail()->signature()->installation();
1450 }
1451
1452 public static function getSalutation(int $a_usr_id, ?ilLanguage $a_language = null): string
1453 {
1454 global $DIC;
1455
1456 $lang = ($a_language instanceof ilLanguage) ? $a_language : $DIC->language();
1457 $lang->loadLanguageModule('mail');
1458
1459 $gender = ilObjUser::_lookupGender($a_usr_id);
1460 $gender = $gender ?: 'n';
1461 $name = ilObjUser::_lookupName($a_usr_id);
1462
1463 if ($name['firstname'] === '') {
1464 return $lang->txt('mail_salutation_anonymous') . ',';
1465 }
1466
1467 return
1468 $lang->txt('mail_salutation_' . $gender) . ' ' .
1469 ($name['title'] ? $name['title'] . ' ' : '') .
1470 ($name['firstname'] ? $name['firstname'] . ' ' : '') .
1471 $name['lastname'] . ',';
1472 }
1473
1474 private function getUserInstanceById(int $usr_id): ?ilObjUser
1475 {
1476 if (!array_key_exists($usr_id, $this->user_instances_by_id_map)) {
1477 try {
1478 $user = new ilObjUser($usr_id);
1479 } catch (Exception) {
1480 $user = null;
1481 }
1482
1483 $this->user_instances_by_id_map[$usr_id] = $user;
1484 }
1485
1486 return $this->user_instances_by_id_map[$usr_id];
1487 }
1488
1492 public function setUserInstanceById(array $user_instances_by_id_map): void
1493 {
1494 $this->user_instances_by_id_map = $user_instances_by_id_map;
1495 }
1496
1497 private function getMailOptionsByUserId(int $usr_id): ilMailOptions
1498 {
1499 if (!isset($this->mail_options_by_usr_id_map[$usr_id])) {
1500 $this->mail_options_by_usr_id_map[$usr_id] = new ilMailOptions($usr_id);
1501 }
1502
1503 return $this->mail_options_by_usr_id_map[$usr_id];
1504 }
1505
1509 public function setMailOptionsByUserIdMap(array $mail_options_by_usr_id_map): void
1510 {
1511 $this->mail_options_by_usr_id_map = $mail_options_by_usr_id_map;
1512 }
1513
1514 public function formatLinebreakMessage(string $message): string
1515 {
1516 return $message;
1517 }
1518
1519 private function createRecipient(int $user_id): Recipient
1520 {
1521 return new Recipient(
1522 $user_id,
1523 $this->getUserInstanceById($user_id),
1524 $this->getMailOptionsByUserId($user_id),
1525 $this->legal_documents
1526 );
1527 }
1528}
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
Builds data types.
Definition: Factory.php:36
withInternalMailId(int $internal_mail_id)
Global event handler.
const CONTEXT_CRON
static getType()
Get context type.
Class ilDBConstants.
static _getLanguage(string $a_lang_key='')
Get language object.
language handling
static getLogger(string $a_component_id)
Get component logger.
Component logger with individual log levels by component id.
static _getIliasMailerName()
sendMimeMail(string $to, string $cc, string $bcc, string $subject, string $message, array $attachments)
int $max_recipient_character_length
getCountRecipient(string $recipients, bool $only_external_addresses=true)
withContextParameters(array $parameters)
sendMailWithoutReplacedPlaceholder(MailDeliveryData $mail_data, array $to_usr_ids, array $cc_bcc_recipients)
deleteMails(array $mail_ids)
parseAddresses(string $addresses)
Explode recipient string, allowed separators are ',' ';' ' '.
getUserIds(array $recipients)
getUserInstanceById(int $usr_id)
moveMailsToFolder(array $mail_ids, int $folder_id)
checkRecipients(string $recipients)
autoresponder()
array $context_parameters
markUnread(array $mail_ids)
readonly ILIAS Refinery Factory $refinery
array $mail_options_by_usr_id_map
const string PROP_CONTEXT_SUBJECT_PREFIX
array $user_instances_by_id_map
formatNamesForOutput(string $recipients)
isSystemMail()
getCountRecipients(string $to_recipients, string $cc_recipients, string $bcc_recipients, bool $only_external_addresses=true)
bool $append_installation_signature
sendMailWithReplacedPlaceholder(MailDeliveryData $mail_data, array $to_usr_ids)
scheduledMail(int $folder_id, int $sender_usr_id, MailScheduleData $mail_data, ?string $template_context_id=null, array $template_context_parameters=[])
sendMailWithReplacedEmptyPlaceholder(MailDeliveryData $mail_data, array $recipients,)
deleteMailsOfFolder(int $folder_id)
appendInstallationSignature(?bool $a_flag=null)
const string ILIAS_HOST
string $table_mail_saved
validateRecipients(string $to, string $cc, string $bcc)
readonly Conductor $legal_documents
retrieveFromStage()
setMailOptionsByUserIdMap(array $mail_options_by_usr_id_map)
static getSalutation(int $a_usr_id, ?ilLanguage $a_language=null)
distributeMail(MailDeliveryData $mail_data)
string $table_mail
static _getInstallationSignature()
sendInternalMail(int $folder_id, int $sender_usr_id, array $attachments, string $to, string $cc, string $bcc, string $status, string $subject, string $message, int $usr_id=0, bool $use_placeholders=false, ?string $template_contenxt_id=null, array $template_context_parameters=[])
__construct(private int $a_user_id, private ?ilMailAddressTypeFactory $mail_address_type_factory=null, private ilMailRfc822AddressParserFactory $mail_address_parser_factory=new ilMailRfc822AddressParserFactory(), private ?ilAppEventHandler $event_handler=null, private ?ilLogger $logger=null, private ?ilDBInterface $db=null, private ?ilLanguage $lng=null, private ?ilFileDataMail $mail_file_data=null, protected ?ilMailOptions $mail_options=null, private ?ilMailbox $mailbox=null, private ?ilMailMimeSenderFactory $sender_factory=null, private ?Closure $usr_id_by_login_callable=null, private ?AutoresponderService $auto_responder_service=null, private ?int $mail_admin_node_ref_id=null, private ?int $mail_obj_ref_id=null, private ?ilObjUser $actor=null, private ?ilMailTemplatePlaceholderResolver $placeholder_resolver=null, private ?ilMailTemplatePlaceholderToEmptyResolver $placeholder_to_empty_resolver=null, ?Conductor $legal_documents=null, ?MailSignatureService $signature_service=null,)
sendChanneledMails(MailDeliveryData $mail_data, array $recipients, string $message)
getSubjectSentFolderId()
array $mail_data
saveInSentbox(array $attachment, string $to, string $cc, string $bcc, string $subject, string $message)
withContextId(string $context_id)
existsRecipient(string $new_recipient, string $existing_recipients)
replacePlaceholders(string $message, int $usr_id=0)
formatLinebreakMessage(string $message)
markRead(array $mail_ids)
countMailsOfFolder(int $folder_id)
setUserInstanceById(array $user_instances_by_id_map)
getMailsOfFolder(int $a_folder_id, array $filter=[])
getEmailRecipients(string $recipients)
delegateExternalEmails(string $subject, array $attachments, string $message, array $usr_id_to_external_email_addresses_map)
string $context_id
checkMail(string $to, string $cc, string $bcc, string $subject)
replacePlaceholdersEmpty(string $message)
int $user_id
static _getAutoGeneratedMessageString(?ilLanguage $lang=null)
createRecipient(int $user_id)
getMailObjectReferenceId()
bool $save_in_sentbox
getPreviousMail(int $mail_id)
bool $append_user_signature
readMailObjectReferenceId()
getNextMail(int $mail_id)
getMail(int $mail_id)
saveAttachments(?ResourceCollectionIdentification $attachments)
enqueue(string $a_rcp_to, string $a_rcp_cc, string $a_rcp_bcc, string $a_m_subject, string $a_m_message, array $a_attachment, bool $a_use_placeholders=false)
Should be used to enqueue a 'mail'.
persistToStage(int $a_user_id, string $a_rcp_to, string $a_rcp_cc, string $a_rcp_bcc, string $a_m_subject, string $a_m_message, ?\ILIAS\ResourceStorage\Identification\ResourceCollectionIdentification $a_attachments=null, bool $a_use_placeholders=false, ?string $a_tpl_context_id=null, ?array $a_tpl_ctx_params=[])
updateDraft(int $a_folder_id, array $a_attachments, string $a_rcp_to, string $a_rcp_cc, string $a_rcp_bcc, string $a_m_subject, string $a_m_message, int $a_draft_id=0, ?DateTimeImmutable $schedule_time=null, bool $a_use_placeholders=false, ?string $a_tpl_context_id=null, array $a_tpl_context_params=[])
getSaveInSentbox()
setSaveInSentbox(bool $save_in_sentbox)
fetchMailData(?array $row)
getNewDraftId(int $folder_id)
getMailOptionsByUserId(int $usr_id)
MailSignatureService $signature_service
sendMail(MailDeliveryData $mail_data)
This method is used to finally send internal messages and external emails To use the mail system as a...
From(ilMailMimeSender $sender)
User class.
static _lookupName(int $a_user_id)
static _lookupId(string|array $a_user_str)
static _lookupPref(int $a_usr_id, string $a_keyword)
static _lookupGender(int $a_user_id)
static strLen(string $a_string)
Definition: class.ilStr.php:60
static _getHttpPath()
const ANONYMOUS_USER_ID
Definition: constants.php:27
return['delivery_method'=> 'php',]
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
const ILIAS_VERSION_NUMERIC
Interface ilDBInterface.
$res
Definition: ltiservices.php:69
Interface Observer \BackgroundTasks Contains several chained tasks and infos about them.
try
handle Lrs Init
Definition: xapiproxy.php:73
global $lng
Definition: privfeed.php:31
if(!file_exists('../ilias.ini.php'))
global $DIC
Definition: shib_login.php:26
$context
Definition: webdav.php:31