95b69459db0c410a7a20e9961f420d4caf7fa284
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Utility / MailUtility.php
1 <?php
2 namespace TYPO3\CMS\Core\Utility;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Core\Database\ConnectionPool;
18 use TYPO3\CMS\Core\Database\Query\Restriction\HiddenRestriction;
19
20 /**
21 * Class to handle mail specific functionality
22 */
23 class MailUtility
24 {
25 /**
26 * Gets a valid "from" for mail messages (email and name).
27 *
28 * Ready to be passed to $mail->setFrom()
29 *
30 * @return array key=Valid email address which can be used as sender, value=Valid name which can be used as a sender. NULL if no address is configured
31 */
32 public static function getSystemFrom()
33 {
34 $address = self::getSystemFromAddress();
35 $name = self::getSystemFromName();
36 if (!$address) {
37 return null;
38 }
39 if ($name) {
40 return [$address => $name];
41 }
42 return [$address];
43 }
44
45 /**
46 * Creates a valid "from" name for mail messages.
47 *
48 * As configured in Install Tool.
49 *
50 * @return string The name (unquoted, unformatted). NULL if none is set
51 */
52 public static function getSystemFromName()
53 {
54 if ($GLOBALS['TYPO3_CONF_VARS']['MAIL']['defaultMailFromName']) {
55 return $GLOBALS['TYPO3_CONF_VARS']['MAIL']['defaultMailFromName'];
56 }
57 return null;
58 }
59
60 /**
61 * Creates a valid email address for the sender of mail messages.
62 *
63 * Uses a fallback chain:
64 * $TYPO3_CONF_VARS['MAIL']['defaultMailFromAddress'] ->
65 * no-reply@FirstDomainRecordFound ->
66 * no-reply@php_uname('n') ->
67 * no-reply@example.com
68 *
69 * Ready to be passed to $mail->setFrom()
70 *
71 * @return string An email address
72 */
73 public static function getSystemFromAddress()
74 {
75 // default, first check the localconf setting
76 $address = $GLOBALS['TYPO3_CONF_VARS']['MAIL']['defaultMailFromAddress'];
77 if (!GeneralUtility::validEmail($address)) {
78 // just get us a domain record we can use as the host
79 $host = '';
80 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
81 ->getQueryBuilderForTable('sys_domain');
82
83 $queryBuilder->getRestrictions()
84 ->removeAll()
85 ->add(GeneralUtility::makeInstance(HiddenRestriction::class));
86
87 $domainRecord = $queryBuilder
88 ->select('domainName')
89 ->from('sys_domain')
90 ->orderBy('pid', 'ASC')
91 ->orderBy('sorting', 'ASC')
92 ->execute()
93 ->fetch();
94
95 if (!empty($domainRecord['domainName'])) {
96 $tempUrl = $domainRecord['domainName'];
97 if (!GeneralUtility::isFirstPartOfStr($tempUrl, 'http')) {
98 // shouldn't be the case anyways, but you never know
99 // ... there're crazy people out there
100 $tempUrl = 'http://' . $tempUrl;
101 }
102 $host = parse_url($tempUrl, PHP_URL_HOST);
103 }
104 $address = 'no-reply@' . $host;
105 if (!GeneralUtility::validEmail($address)) {
106 // still nothing, get host name from server
107 $address = 'no-reply@' . php_uname('n');
108 if (!GeneralUtility::validEmail($address)) {
109 // if everything fails use a dummy address
110 $address = 'no-reply@example.com';
111 }
112 }
113 }
114 return $address;
115 }
116
117 /**
118 * Gets a default "reply-to" for mail messages (email and name).
119 *
120 * Ready to be passed to $mail->setReplyTo()
121 *
122 * @return array List of email-addresses. Specifying a realname can be done in the form of "replyToName <replyTo@example.com>".
123 */
124 public static function getSystemReplyTo(): array
125 {
126 $mailConfiguration = $GLOBALS['TYPO3_CONF_VARS']['MAIL'];
127 $replyToAddress = $mailConfiguration['defaultMailReplyToAddress'];
128 if (empty($replyToAddress) || !GeneralUtility::validEmail($replyToAddress)) {
129 return [];
130 }
131
132 if (!empty($mailConfiguration['defaultMailReplyToName'])) {
133 $replyTo = [$replyToAddress => $mailConfiguration['defaultMailReplyToName']];
134 } else {
135 $replyTo = [$replyToAddress];
136 }
137
138 return $replyTo;
139 }
140
141 /**
142 * Breaks up a single line of text for emails
143 * Words - longer than $lineWidth - will not be split into parts
144 *
145 * @param string $str The string to break up
146 * @param string $newlineChar The string to implode the broken lines with (default/typically \n)
147 * @param int $lineWidth The line width
148 * @return string Reformated text
149 */
150 public static function breakLinesForEmail($str, $newlineChar = LF, $lineWidth = 76)
151 {
152 $lines = [];
153 $substrStart = 0;
154 while (strlen($str) > $substrStart) {
155 $substr = substr($str, $substrStart, $lineWidth);
156 // has line exceeded (reached) the maximum width?
157 if (strlen($substr) == $lineWidth) {
158 // find last space-char
159 $spacePos = strrpos(rtrim($substr), ' ');
160 // space-char found?
161 if ($spacePos !== false) {
162 // take everything up to last space-char
163 $theLine = substr($substr, 0, $spacePos);
164 $substrStart++;
165 } else {
166 // search for space-char in remaining text
167 // makes this line longer than $lineWidth!
168 $afterParts = explode(' ', substr($str, $lineWidth + $substrStart), 2);
169 $theLine = $substr . $afterParts[0];
170 }
171 if ($theLine === '') {
172 // prevent endless loop because of empty line
173 break;
174 }
175 } else {
176 $theLine = $substr;
177 }
178 $lines[] = trim($theLine);
179 $substrStart += strlen($theLine);
180 if (trim(substr($str, $substrStart, $lineWidth)) === '') {
181 // no more text
182 break;
183 }
184 }
185 return implode($newlineChar, $lines);
186 }
187
188 /**
189 * Parses mailbox headers and turns them into an array.
190 *
191 * Mailbox headers are a comma separated list of 'name <email@example.org>' combinations
192 * or plain email addresses (or a mix of these).
193 * The resulting array has key-value pairs where the key is either a number
194 * (no display name in the mailbox header) and the value is the email address,
195 * or the key is the email address and the value is the display name.
196 *
197 * @param string $rawAddresses Comma separated list of email addresses (optionally with display name)
198 * @return array Parsed list of addresses.
199 */
200 public static function parseAddresses($rawAddresses)
201 {
202 /** @var \TYPO3\CMS\Core\Mail\Rfc822AddressesParser $addressParser */
203 $addressParser = GeneralUtility::makeInstance(
204 \TYPO3\CMS\Core\Mail\Rfc822AddressesParser::class,
205 $rawAddresses
206 );
207 $addresses = $addressParser->parseAddressList();
208 $addressList = [];
209 foreach ($addresses as $address) {
210 if ($address->mailbox === '') {
211 continue;
212 }
213 if ($address->personal) {
214 // item with name found ( name <email@example.org> )
215 $addressList[$address->mailbox . '@' . $address->host] = $address->personal;
216 } else {
217 // item without name found ( email@example.org )
218 $addressList[] = $address->mailbox . '@' . $address->host;
219 }
220 }
221 return $addressList;
222 }
223 }