3 * @copyright Copyright (C) 2010-2021, the Friendica project
5 * @license GNU AGPL version 3 or any later version
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as
9 * published by the Free Software Foundation, either version 3 of the
10 * License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22 namespace Friendica\Util\EMailer;
25 use Friendica\App\BaseURL;
26 use Friendica\Core\Config\Capability\IManageConfigValues;
27 use Friendica\Core\L10n;
28 use Friendica\Core\Renderer;
29 use Friendica\Model\User;
30 use Friendica\Network\HTTPException\UnprocessableEntityException;
31 use Friendica\Object\Email;
32 use Friendica\Object\EMail\IEmail;
33 use Psr\Log\LoggerInterface;
36 * A base class for building new emails
38 abstract class MailBuilder
40 /** @var string The default email banner in case nothing else is defined */
41 const DEFAULT_EMAIL_BANNER = 'images/friendica-32.png';
45 /** @var IManageConfigValues */
49 /** @var LoggerInterface */
52 /** @var string[][] */
56 protected $senderName = null;
58 protected $senderAddress = null;
60 protected $senderNoReply = null;
63 protected $recipientAddress = null;
65 protected $recipientUid = null;
67 public function __construct(L10n $l10n, BaseURL $baseUrl, IManageConfigValues $config, LoggerInterface $logger)
70 $this->baseUrl = $baseUrl;
71 $this->config = $config;
72 $this->logger = $logger;
74 $hostname = $baseUrl->getHostname();
75 if (strpos($hostname, ':')) {
76 $hostname = substr($hostname, 0, strpos($hostname, ':'));
80 'Precedence' => ['list'],
81 'X-Friendica-Host' => [$hostname],
82 'X-Friendica-Platform' => [FRIENDICA_PLATFORM],
83 'X-Friendica-Version' => [FRIENDICA_VERSION],
84 'List-ID' => ['<notification.' . $hostname . '>'],
85 'List-Archive' => ['<' . $baseUrl->get() . '/notifications/system>'],
90 * Gets the subject of the concrete builder, which inherits this base class
94 abstract protected function getSubject();
97 * Gets the HTML version of the body of the concrete builder, which inherits this base class
101 abstract protected function getHtmlMessage();
104 * Gets the Plaintext version of the body of the concrete builder, which inherits this base class
108 abstract protected function getPlaintextMessage();
111 * Adds the User ID to the email in case the mail sending needs additional properties of this user
113 * @param array $user The user entity/array, for which the email should be sent
116 * @todo Once the user array is replaced with a user entity, replace this array parameter as well
118 public function forUser(array $user)
120 $this->recipientUid = $user['uid'] ?? 0;
122 $this->l10n = $user['language'] ? $this->l10n->withLang($user['language']) : $this->l10n;
123 } catch (Exception $e) {
124 $this->logger->warning('cannot use language.', ['user' => $user, 'exception' => $e]);
131 * Adds the sender to the email (if not called/set, the sender will get loaded with the help of the user id)
133 * @param string $name The name of the sender
134 * @param string $address The (email) address of the sender
135 * @param string|null $noReply Optional "no-reply" (email) address (if not set, it's the same as the address)
139 public function withSender(string $name, string $address, string $noReply = null)
141 $this->senderName = $name;
142 $this->senderAddress = $address;
143 $this->senderNoReply = $noReply ?? $this->senderNoReply;
149 * Adds a recipient to the email
151 * @param string $address The (email) address of the recipient
155 public function withRecipient(string $address)
157 $this->recipientAddress = $address;
163 * Returns the current headers
167 public function getHeaders()
169 return $this->headers;
177 * 'Header1' => ['value1', 'value2', ...],
178 * 'Header2' => ['value3', 'value4', ...],
182 * @param string[][] $headers
185 public function withHeaders(array $headers)
187 $this->headers = $headers;
193 * Adds a value to a header
195 * @param string $name The header name
196 * @param string $value The value of the header to add
200 public function addHeader(string $name, string $value)
202 $this->headers[$name][] = $value;
208 * Sets a value to a header (overwrites existing values)
210 * @param string $name The header name
211 * @param string $value The value to set
215 public function setHeader(string $name, string $value)
217 $this->headers[$name] = [$value];
223 * Build a email based on the given attributes
225 * @param bool $raw True, if the email shouldn't get extended by the default email-template
227 * @return IEmail A new generated email
229 * @throws UnprocessableEntityException
232 public function build(bool $raw = false)
234 if ((empty($this->recipientAddress)) &&
235 !empty($this->recipientUid)) {
236 $user = User::getById($this->recipientUid, ['email']);
238 if (!empty($user['email'])) {
239 $this->recipientAddress = $user['email'];
243 if (empty($this->recipientAddress)) {
244 throw new UnprocessableEntityException('Recipient address is missing.');
247 if (empty($this->senderAddress) || empty($this->senderName)) {
248 throw new UnprocessableEntityException('Sender address or name is missing.');
251 $this->senderNoReply = $this->senderNoReply ?? $this->senderAddress;
253 $msgHtml = $this->getHtmlMessage() ?? '';
256 // load the template for private message notifications
257 $tpl = Renderer::getMarkupTemplate('email/html.tpl');
258 $msgHtml = Renderer::replaceMacros($tpl, [
259 '$title' => $this->l10n->t('Friendica Notification'),
260 '$product' => FRIENDICA_PLATFORM,
261 '$htmlversion' => $msgHtml,
262 '$sitename' => $this->config->get('config', 'sitename'),
263 '$banner' => $this->config->get('system', 'email_banner',
264 $this->baseUrl->get(true) . DIRECTORY_SEPARATOR . self::DEFAULT_EMAIL_BANNER),
270 $this->senderAddress,
271 $this->senderNoReply,
272 $this->recipientAddress,
273 $this->getSubject() ?? '',
275 $this->getPlaintextMessage() ?? '',
277 $this->recipientUid ?? null);