├── CHANGELOG.md
├── LICENSE.md
├── README.md
├── UPGRADE.md
├── composer.json
├── config
├── common.php
└── params.php
└── src
├── Mailer.php
└── Message.php
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Yii Mailer Library - Swift Mailer Extension Change Log
2 |
3 |
4 | ## 3.0.2 under development
5 |
6 | - no changes in this release.
7 |
8 |
9 | ## 3.0.1 August 30, 2021
10 |
11 | - Chg #45: Use definitions from `yiisoft/definitions` in configuration (vjik)
12 |
13 | ## 3.0.0 August 25, 2021
14 |
15 | - New #44: Add methods to `Yiisoft\Mailer\SwiftMailer\Message`: `getDate()`, `withDate()`, `getSender()`, `withSender()` (devanych)
16 | - Bug #44: Add normalization of return value to `Yiisoft\Mailer\SwiftMailer\Message` getters: `getFrom()`, `getTo()`, `getCc()`, `getBcc()` (devanych)
17 |
18 | ## 2.0.0 August 24, 2021
19 |
20 | - Chg: Use yiisoft/mailer ^2.0 (samdark)
21 |
22 | ## 1.0.0 July 05, 2021
23 |
24 | Initial release.
25 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | Copyright © 2008 by Yii Software (https://www.yiiframework.com/)
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions
6 | are met:
7 |
8 | * Redistributions of source code must retain the above copyright
9 | notice, this list of conditions and the following disclaimer.
10 | * Redistributions in binary form must reproduce the above copyright
11 | notice, this list of conditions and the following disclaimer in
12 | the documentation and/or other materials provided with the
13 | distribution.
14 | * Neither the name of Yii Software nor the names of its
15 | contributors may be used to endorse or promote products derived
16 | from this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22 | COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 | POSSIBILITY OF SUCH DAMAGE.
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | This package is deprecated in favor of
4 | Symfony Mailer Extension.
5 |
6 |
7 |
8 | See details in article
9 | The end of Swiftmailer
10 | by Fabien Potencier.
11 |
12 |
13 | ❌
14 |
15 |
16 | ---
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
Yii Mailer Library - Swift Mailer Extension
26 |
27 |
28 |
29 | [](https://packagist.org/packages/yiisoft/mailer-swiftmailer)
30 | [](https://packagist.org/packages/yiisoft/mailer-swiftmailer)
31 | [](https://github.com/yiisoft/mailer-swiftmailer/actions?query=workflow%3Abuild)
32 | [](https://scrutinizer-ci.com/g/yiisoft/mailer-swiftmailer/?branch=master)
33 | [](https://scrutinizer-ci.com/g/yiisoft/mailer-swiftmailer/?branch=master)
34 | [](https://dashboard.stryker-mutator.io/reports/github.com/yiisoft/mailer-swiftmailer/master)
35 | [](https://github.com/yiisoft/mailer-swiftmailer/actions?query=workflow%3A%22static+analysis%22)
36 | [](https://shepherd.dev/github/yiisoft/mailer-swiftmailer)
37 |
38 | This package is a [yiisoft/mailer](https://github.com/yiisoft/mailer) library implementation that provides
39 | a [Swift Mailer](https://swiftmailer.symfony.com/) mail solution.
40 |
41 | ## Installation
42 |
43 | The package could be installed with composer:
44 |
45 | ```
46 | composer require yiisoft/mailer-swiftmailer --prefer-dist
47 | ```
48 |
49 | ## General usage
50 |
51 | Creating a mailer:
52 |
53 | ```php
54 | use Yiisoft\Mailer\MessageBodyRenderer;
55 | use Yiisoft\Mailer\MessageBodyTemplate;
56 | use Yiisoft\Mailer\MessageFactory;
57 | use Yiisoft\Mailer\SwiftMailer\Mailer;
58 | use Yiisoft\Mailer\SwiftMailer\Message;
59 |
60 | /**
61 | * @var \Psr\EventDispatcher\EventDispatcherInterface $dispatcher
62 | * @var \Swift_Events_EventListener[] $plugins
63 | * @var \Swift_Transport $transport
64 | * @var \Yiisoft\View\View $view
65 | */
66 |
67 | $template = new MessageBodyTemplate('/path/to/directory/of/view-files');
68 |
69 | $mailer = new Mailer(
70 | new MessageFactory(Message::class),
71 | new MessageBodyRenderer($view, $template),
72 | $dispatcher,
73 | $transport,
74 | $plugins, // By default, an empty array
75 | );
76 | ```
77 |
78 | Sending a mail message:
79 |
80 | ```php
81 | $message = $mailer
82 | ->compose()
83 | ->withFrom('from@domain.com')
84 | ->withTo('to@domain.com')
85 | ->withSubject('Message subject')
86 | ->withTextBody('Plain text content')
87 | ->withHtmlBody('HTML content')
88 | ;
89 | $mailer->send($message);
90 | // Or several
91 | $mailer->sendMultiple([$message]);
92 | ```
93 |
94 | Additional methods of the `Yiisoft\Mailer\SwiftMailer\Message`:
95 |
96 | - `getSwiftMessage()` - Returns a Swift message instance.
97 | - `getReadReceiptTo()` - Returns the addresses to which a read-receipt will be sent.
98 | - `withReadReceiptTo()` - Returns a new instance with the specified ask for a delivery receipt from the recipient to be sent to address.
99 | - `withAttachedSigners()` - Returns a new instance with the specified attached signers.
100 |
101 | For use in the [Yii framework](http://www.yiiframework.com/), see the configuration files:
102 |
103 | - [`config/common.php`](https://github.com/yiisoft/mailer-swiftmailer/blob/master/config/common.php)
104 | - [`config/params.php`](https://github.com/yiisoft/mailer-swiftmailer/blob/master/config/params.php)
105 |
106 | See [Yii guide to mailing](https://github.com/yiisoft/docs/blob/master/guide/en/tutorial/mailing.md) for more info.
107 |
108 | ## Testing
109 |
110 | ### Unit testing
111 |
112 | The package is tested with [PHPUnit](https://phpunit.de/). To run tests:
113 |
114 | ```shell
115 | ./vendor/bin/phpunit
116 | ```
117 |
118 | ### Mutation testing
119 |
120 | The package tests are checked with [Infection](https://infection.github.io/) mutation framework with
121 | [Infection Static Analysis Plugin](https://github.com/Roave/infection-static-analysis-plugin). To run it:
122 |
123 | ```shell
124 | ./vendor/bin/roave-infection-static-analysis-plugin
125 | ```
126 |
127 | ### Static analysis
128 |
129 | The code is statically analyzed with [Psalm](https://psalm.dev/). To run static analysis:
130 |
131 | ```shell
132 | ./vendor/bin/psalm
133 | ```
134 |
135 | ## License
136 |
137 | The Yii Framework Swift Mailer Extension is free software. It is released under the terms of the BSD License.
138 | Please see [`LICENSE`](./LICENSE.md) for more information.
139 |
140 | Maintained by [Yii Software](https://www.yiiframework.com/).
141 |
142 | ## Support the project
143 |
144 | [](https://opencollective.com/yiisoft)
145 |
146 | ## Follow updates
147 |
148 | [](https://www.yiiframework.com/)
149 | [](https://twitter.com/yiiframework)
150 | [](https://t.me/yii3en)
151 | [](https://www.facebook.com/groups/yiitalk)
152 | [](https://yiiframework.com/go/slack)
153 |
--------------------------------------------------------------------------------
/UPGRADE.md:
--------------------------------------------------------------------------------
1 | Upgrading Instructions
2 | ======================
3 |
4 | Changes summary:
5 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "yiisoft/mailer-swiftmailer",
3 | "description": "Yii Mailer Library - Swift Mailer Extension",
4 | "keywords": [
5 | "yii",
6 | "swift",
7 | "swiftmailer",
8 | "mail",
9 | "email",
10 | "mailer"
11 | ],
12 | "type": "library",
13 | "license": "BSD-3-Clause",
14 | "support": {
15 | "issues": "https://github.com/yiisoft/mailer-swiftmailer/issues?state=open",
16 | "forum": "https://www.yiiframework.com/forum/",
17 | "wiki": "https://www.yiiframework.com/wiki/",
18 | "irc": "irc://irc.freenode.net/yii",
19 | "chat": "https://t.me/yii3en",
20 | "source": "https://github.com/yiisoft/mailer-swiftmailer"
21 | },
22 | "funding": [
23 | {
24 | "type": "opencollective",
25 | "url": "https://opencollective.com/yiisoft"
26 | },
27 | {
28 | "type": "github",
29 | "url": "https://github.com/sponsors/yiisoft"
30 | }
31 | ],
32 | "require": {
33 | "php": "^7.4|^8.0",
34 | "swiftmailer/swiftmailer": "^6.2",
35 | "yiisoft/mailer": "^3.0"
36 | },
37 | "require-dev": {
38 | "phpunit/phpunit": "^9.5",
39 | "roave/infection-static-analysis-plugin": "^1.16",
40 | "spatie/phpunit-watcher": "^1.23",
41 | "vimeo/psalm": "^4.18",
42 | "yiisoft/files": "^1.0",
43 | "yiisoft/psr-dummy-provider": "^1.0",
44 | "yiisoft/test-support": "^1.3"
45 | },
46 | "suggest": {
47 | "ext-openssl": "Required for SMimeSigner"
48 | },
49 | "autoload": {
50 | "psr-4": {
51 | "Yiisoft\\Mailer\\SwiftMailer\\": "src"
52 | }
53 | },
54 | "autoload-dev": {
55 | "psr-4": {
56 | "Yiisoft\\Mailer\\SwiftMailer\\Tests\\": "tests"
57 | }
58 | },
59 | "extra": {
60 | "config-plugin-options": {
61 | "source-directory": "config"
62 | },
63 | "config-plugin": {
64 | "params": "params.php",
65 | "common": "common.php"
66 | }
67 | },
68 | "config": {
69 | "sort-packages": true,
70 | "allow-plugins": {
71 | "infection/extension-installer": true,
72 | "composer/package-versions-deprecated": true
73 | }
74 | },
75 | "scripts": {
76 | "test": "phpunit --testdox --no-interaction",
77 | "test-watch": "phpunit-watcher watch"
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/config/common.php:
--------------------------------------------------------------------------------
1 | [
22 | 'class' => MessageBodyRenderer::class,
23 | '__construct()' => [
24 | Reference::to(View::class),
25 | DynamicReference::to(static fn (Aliases $aliases) => new MessageBodyTemplate(
26 | $aliases->get($params['yiisoft/mailer']['messageBodyTemplate']['viewPath']),
27 | )),
28 | ],
29 | ],
30 |
31 | MessageFactoryInterface::class => [
32 | 'class' => MessageFactory::class,
33 | '__construct()' => [
34 | Message::class,
35 | ],
36 | ],
37 |
38 | Swift_SmtpTransport::class => [
39 | 'class' => Swift_SmtpTransport::class,
40 | '__construct()' => [
41 | $params['swiftmailer/swiftmailer']['SwiftSmtpTransport']['host'],
42 | $params['swiftmailer/swiftmailer']['SwiftSmtpTransport']['port'],
43 | $params['swiftmailer/swiftmailer']['SwiftSmtpTransport']['encryption'],
44 | ],
45 | 'setUsername()' => [$params['swiftmailer/swiftmailer']['SwiftSmtpTransport']['username']],
46 | 'setPassword()' => [$params['swiftmailer/swiftmailer']['SwiftSmtpTransport']['password']],
47 | ],
48 |
49 | Swift_Transport::class => $params['yiisoft/mailer']['useSendmail']
50 | ? Swift_SendmailTransport::class : Swift_SmtpTransport::class,
51 |
52 | FileMailer::class => [
53 | 'class' => FileMailer::class,
54 | '__construct()' => [
55 | 'path' => DynamicReference::to(fn (Aliases $aliases) => $aliases->get(
56 | $params['yiisoft/mailer']['fileMailer']['fileMailerStorage']
57 | )),
58 | ],
59 | ],
60 |
61 | MailerInterface::class => $params['yiisoft/mailer']['writeToFiles']
62 | ? FileMailer::class : Mailer::class,
63 | ];
64 |
--------------------------------------------------------------------------------
/config/params.php:
--------------------------------------------------------------------------------
1 | [
7 | 'messageBodyTemplate' => [
8 | 'viewPath' => '@resources/mail',
9 | ],
10 | 'fileMailer' => [
11 | 'fileMailerStorage' => '@runtime/mail',
12 | ],
13 | 'useSendmail' => false,
14 | 'writeToFiles' => true,
15 | ],
16 | 'swiftmailer/swiftmailer' => [
17 | 'SwiftSmtpTransport' => [
18 | 'host' => 'smtp.example.com',
19 | 'port' => 25,
20 | 'encryption' => null,
21 | 'username' => 'admin@example.com',
22 | 'password' => '',
23 | ],
24 | ],
25 | ];
26 |
--------------------------------------------------------------------------------
/src/Mailer.php:
--------------------------------------------------------------------------------
1 | swiftMailer = new Swift_Mailer($transport);
42 |
43 | foreach ($plugins as $plugin) {
44 | $this->swiftMailer->registerPlugin($plugin);
45 | }
46 | }
47 |
48 | protected function sendMessage(MessageInterface $message): void
49 | {
50 | /** @var Message $message */
51 | $sent = $this->swiftMailer->send($message->getSwiftMessage());
52 |
53 | if ($sent === 0) {
54 | throw new RuntimeException('Unable send message.');
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/Message.php:
--------------------------------------------------------------------------------
1 | swiftMessage = new Swift_Message();
38 | }
39 |
40 | public function __clone()
41 | {
42 | $this->swiftMessage = clone $this->swiftMessage;
43 | }
44 |
45 | public function getCharset(): string
46 | {
47 | return $this->swiftMessage->getCharset();
48 | }
49 |
50 | public function withCharset(string $charset): self
51 | {
52 | $new = clone $this;
53 | $new->swiftMessage->setCharset($charset);
54 | return $new;
55 | }
56 |
57 | public function getFrom()
58 | {
59 | return $this->normalizeAddresses($this->swiftMessage->getFrom());
60 | }
61 |
62 | public function withFrom($from): self
63 | {
64 | $new = clone $this;
65 | $new->swiftMessage->setFrom($from);
66 | return $new;
67 | }
68 |
69 | public function getTo()
70 | {
71 | return $this->normalizeAddresses($this->swiftMessage->getTo());
72 | }
73 |
74 | public function withTo($to): self
75 | {
76 | $new = clone $this;
77 | $new->swiftMessage->setTo($to);
78 | return $new;
79 | }
80 |
81 | public function getReplyTo()
82 | {
83 | return $this->normalizeAddresses($this->swiftMessage->getReplyTo());
84 | }
85 |
86 | public function withReplyTo($replyTo): self
87 | {
88 | $new = clone $this;
89 | $new->swiftMessage->setReplyTo($replyTo);
90 | return $new;
91 | }
92 |
93 | public function getCc()
94 | {
95 | return $this->normalizeAddresses($this->swiftMessage->getCc());
96 | }
97 |
98 | public function withCc($cc): self
99 | {
100 | $new = clone $this;
101 | $new->swiftMessage->setCc($cc);
102 | return $new;
103 | }
104 |
105 | public function getBcc()
106 | {
107 | return $this->normalizeAddresses($this->swiftMessage->getBcc());
108 | }
109 |
110 | public function withBcc($bcc): self
111 | {
112 | $new = clone $this;
113 | $new->swiftMessage->setBcc($bcc);
114 | return $new;
115 | }
116 |
117 | public function getSubject(): string
118 | {
119 | /** @psalm-suppress RedundantCastGivenDocblockType */
120 | return (string) $this->swiftMessage->getSubject();
121 | }
122 |
123 | public function withSubject(string $subject): self
124 | {
125 | $new = clone $this;
126 | $new->swiftMessage->setSubject($subject);
127 | return $new;
128 | }
129 |
130 | public function getDate(): ?DateTimeImmutable
131 | {
132 | return $this->date;
133 | }
134 |
135 | public function withDate(DateTimeInterface $date): self
136 | {
137 | if ($date instanceof DateTime) {
138 | $immutable = new DateTimeImmutable('@' . $date->getTimestamp());
139 | $date = $immutable->setTimezone($date->getTimezone());
140 | }
141 |
142 | $new = $this->withHeader('Date', $date->format(DateTimeInterface::RFC2822));
143 | $new->date = $date;
144 | return $new;
145 | }
146 |
147 | public function getPriority(): int
148 | {
149 | /** @psalm-suppress RedundantCastGivenDocblockType */
150 | return (int) $this->swiftMessage->getPriority();
151 | }
152 |
153 | public function withPriority(int $priority): self
154 | {
155 | $new = clone $this;
156 | $new->swiftMessage->setPriority($priority);
157 | return $new;
158 | }
159 |
160 | public function getReturnPath(): string
161 | {
162 | /** @psalm-suppress RedundantCastGivenDocblockType */
163 | return (string) $this->swiftMessage->getReturnPath();
164 | }
165 |
166 | public function withReturnPath(string $address): self
167 | {
168 | $new = clone $this;
169 | $new->swiftMessage->setReturnPath($address);
170 | return $new;
171 | }
172 |
173 | public function getSender(): string
174 | {
175 | /** @var array|null $sender */
176 | $sender = $this->swiftMessage->getSender();
177 | /** @psalm-suppress RedundantCastGivenDocblockType */
178 | return empty($sender) ? '' : (string) array_key_first($sender);
179 | }
180 |
181 | public function withSender(string $address): self
182 | {
183 | $new = clone $this;
184 | $new->swiftMessage->setSender($address);
185 | return $new;
186 | }
187 |
188 | public function getTextBody(): string
189 | {
190 | /** @psalm-suppress RedundantCastGivenDocblockType */
191 | return (string) $this->swiftMessage->getBody();
192 | }
193 |
194 | public function withTextBody(string $text): self
195 | {
196 | $new = clone $this;
197 | $new->setBody($text, 'text/plain');
198 | return $new;
199 | }
200 |
201 | public function getHtmlBody(): string
202 | {
203 | /** @psalm-suppress RedundantCastGivenDocblockType */
204 | return (string) $this->swiftMessage->getBody();
205 | }
206 |
207 | public function withHtmlBody(string $html): self
208 | {
209 | $new = clone $this;
210 | $new->setBody($html, 'text/html');
211 | return $new;
212 | }
213 |
214 | public function withAttached(File $file): self
215 | {
216 | $attachment = $file->path() === null
217 | ? new Swift_Attachment($file->content())
218 | : Swift_Attachment::fromPath($file->path())
219 | ;
220 |
221 | if (!empty($file->name())) {
222 | $attachment->setFilename($file->name());
223 | }
224 |
225 | if (!empty($file->contentType())) {
226 | $attachment->setContentType($file->contentType());
227 | }
228 |
229 | $new = clone $this;
230 | $new->swiftMessage->attach($attachment);
231 | return $new;
232 | }
233 |
234 | public function withEmbedded(File $file): self
235 | {
236 | $embedFile = $file->path() === null
237 | ? new Swift_EmbeddedFile($file->content())
238 | : Swift_EmbeddedFile::fromPath($file->path())
239 | ;
240 |
241 | if (!empty($file->name())) {
242 | $embedFile->setFilename($file->name());
243 | }
244 |
245 | if (!empty($file->contentType())) {
246 | $embedFile->setContentType($file->contentType());
247 | }
248 |
249 | $new = clone $this;
250 | $new->swiftMessage->embed($embedFile->setId($file->id()));
251 | return $new;
252 | }
253 |
254 | public function getHeader(string $name): array
255 | {
256 | $headerSet = $this->swiftMessage->getHeaders();
257 |
258 | if (!$headerSet->has($name)) {
259 | return [];
260 | }
261 |
262 | $headers = [];
263 |
264 | /** @var Swift_Mime_Headers_UnstructuredHeader $header */
265 | foreach ($headerSet->getAll($name) as $header) {
266 | $headers[] = $header->getValue();
267 | }
268 |
269 | return $headers;
270 | }
271 |
272 | public function withAddedHeader(string $name, string $value): self
273 | {
274 | $new = clone $this;
275 | $new->swiftMessage
276 | ->getHeaders()
277 | ->addTextHeader($name, $value);
278 | return $new;
279 | }
280 |
281 | public function withHeader(string $name, $value): self
282 | {
283 | $new = clone $this;
284 | $headerSet = $new->swiftMessage->getHeaders();
285 |
286 | if ($headerSet->has($name)) {
287 | $headerSet->remove($name);
288 | }
289 |
290 | foreach ((array) $value as $v) {
291 | $headerSet->addTextHeader($name, $v);
292 | }
293 |
294 | return $new;
295 | }
296 |
297 | public function withHeaders(array $headers): self
298 | {
299 | $new = clone $this;
300 |
301 | foreach ($headers as $name => $value) {
302 | $new = $new->withHeader($name, $value);
303 | }
304 |
305 | return $new;
306 | }
307 |
308 | public function getError(): ?Throwable
309 | {
310 | return $this->error;
311 | }
312 |
313 | public function withError(Throwable $e): self
314 | {
315 | $new = clone $this;
316 | $new->error = $e;
317 | return $new;
318 | }
319 |
320 | public function __toString(): string
321 | {
322 | return $this->swiftMessage->toString();
323 | }
324 |
325 | /**
326 | * Returns a Swift message instance.
327 | *
328 | * @return Swift_Message Swift message instance.
329 | */
330 | public function getSwiftMessage(): Swift_Message
331 | {
332 | return $this->swiftMessage;
333 | }
334 |
335 | /**
336 | * Returns the addresses to which a read-receipt will be sent.
337 | *
338 | * @return array|string The receipt receive email addresses.
339 | */
340 | public function getReadReceiptTo()
341 | {
342 | return $this->normalizeAddresses($this->swiftMessage->getReadReceiptTo());
343 | }
344 |
345 | /**
346 | * Returns a new instance with the specified ask for a delivery receipt from the recipient to be sent to addresses.
347 | *
348 | * @param string|string[] $addresses The receipt receive email address(es).
349 | *
350 | * @return self
351 | */
352 | public function withReadReceiptTo($addresses): self
353 | {
354 | $new = clone $this;
355 | $new->swiftMessage->setReadReceiptTo((array) $addresses);
356 | return $new;
357 | }
358 |
359 | /**
360 | * Returns a new instance with the specified attached signers.
361 | *
362 | * @param Swift_Signer[] $signers
363 | *
364 | * @return self
365 | */
366 | public function withAttachedSigners(array $signers): self
367 | {
368 | $new = clone $this;
369 |
370 | foreach ($signers as $signer) {
371 | $new->swiftMessage->attachSigner($signer);
372 | }
373 |
374 | return $new;
375 | }
376 |
377 | /**
378 | * Sets the message body.
379 | *
380 | * If body is already set and its content type matches given one, it will
381 | * be overridden, if content type miss match the multipart message will be composed.
382 | *
383 | * @param string $body The body content.
384 | * @param string $contentType The body content type.
385 | */
386 | private function setBody(string $body, string $contentType): void
387 | {
388 | $oldBody = $this->swiftMessage->getBody();
389 | $charset = $this->swiftMessage->getCharset();
390 |
391 | if (!empty($oldBody)) {
392 | $oldContentType = $this->swiftMessage->getContentType();
393 |
394 | if ($oldContentType === $contentType) {
395 | $this->swiftMessage->setBody($body, $contentType);
396 | return;
397 | }
398 |
399 | $this->swiftMessage->setBody(null);
400 | /** @psalm-suppress NullArgument */
401 | $this->swiftMessage->setContentType(null);
402 | $this->swiftMessage->addPart($oldBody, $oldContentType, $charset);
403 | $this->swiftMessage->addPart($body, $contentType, $charset);
404 | return;
405 | }
406 |
407 | $parts = $this->swiftMessage->getChildren();
408 | $partFound = false;
409 |
410 | foreach ($parts as $key => $part) {
411 | if ($part instanceof Swift_Mime_MimePart && $part->getContentType() === $contentType) {
412 | $charset = $part->getCharset();
413 | unset($parts[$key]);
414 | $partFound = true;
415 | break;
416 | }
417 | }
418 |
419 | if (!$partFound) {
420 | $this->swiftMessage->setBody($body, $contentType);
421 | return;
422 | }
423 |
424 | reset($parts);
425 | $this->swiftMessage->setChildren($parts);
426 | $this->swiftMessage->addPart($body, $contentType, $charset);
427 | }
428 |
429 | /**
430 | * Normalizes email addresses and names to the correct format.
431 | *
432 | * @param mixed $addresses
433 | *
434 | * @return array|string
435 | */
436 | private function normalizeAddresses($addresses)
437 | {
438 | if (empty($addresses)) {
439 | return '';
440 | }
441 |
442 | if (is_string($addresses)) {
443 | return $addresses;
444 | }
445 |
446 | $normalized = [];
447 |
448 | /** @var mixed $name */
449 | foreach ((array) $addresses as $address => $name) {
450 | $normalized[(string) $address] = is_string($name) ? $name : '';
451 | }
452 |
453 | return $normalized;
454 | }
455 | }
456 |
--------------------------------------------------------------------------------