Passed
Push — 4.7 ( 705b74...d2fa64 )
by Maxime
07:37
created

Email::invalidateBody()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 5
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace SilverStripe\Control\Email;
4
5
use SilverStripe\Control\Director;
6
use SilverStripe\Control\HTTP;
7
use SilverStripe\Core\Convert;
8
use SilverStripe\Core\Environment;
9
use SilverStripe\Core\Injector\Injector;
10
use SilverStripe\ORM\FieldType\DBDatetime;
11
use SilverStripe\ORM\FieldType\DBField;
12
use SilverStripe\ORM\FieldType\DBHTMLText;
13
use SilverStripe\View\Requirements;
14
use SilverStripe\View\SSViewer;
15
use SilverStripe\View\ThemeResourceLoader;
16
use SilverStripe\View\ViewableData;
17
use Swift_Message;
18
use Swift_MimePart;
19
20
/**
21
 * Class to support sending emails.
22
 */
23
class Email extends ViewableData
24
{
25
26
    /**
27
     * @var array
28
     * @config
29
     */
30
    private static $send_all_emails_to = [];
31
32
    /**
33
     * @var array
34
     * @config
35
     */
36
    private static $cc_all_emails_to = [];
37
38
    /**
39
     * @var array
40
     * @config
41
     */
42
    private static $bcc_all_emails_to = [];
43
44
    /**
45
     * @var array
46
     * @config
47
     */
48
    private static $send_all_emails_from = [];
49
50
    /**
51
     * This will be set in the config on a site-by-site basis
52
     * @see https://docs.silverstripe.org/en/4/developer_guides/email/#administrator-emails
53
     *
54
     * @config
55
     * @var string|array The default administrator email address or array of [email => name]
56
     */
57
    private static $admin_email = null;
58
59
    /**
60
     * @var Swift_Message
61
     */
62
    private $swiftMessage;
63
64
    /**
65
     * @var string The name of the HTML template to render the email with (without *.ss extension)
66
     */
67
    private $HTMLTemplate = null;
68
69
    /**
70
     * @var string The name of the plain text template to render the plain part of the email with
71
     */
72
    private $plainTemplate = null;
73
74
    /**
75
     * @var Swift_MimePart
76
     */
77
    private $plainPart;
78
79
    /**
80
     * @var array|ViewableData Additional data available in a template.
81
     * Used in the same way than {@link ViewableData->customize()}.
82
     */
83
    private $data = [];
84
85
    /**
86
     * @var array
87
     */
88
    private $failedRecipients = [];
89
90
    /**
91
     * Checks for RFC822-valid email format.
92
     *
93
     * @param string $address
94
     * @return boolean
95
     *
96
     * @copyright Cal Henderson <[email protected]>
97
     *    This code is licensed under a Creative Commons Attribution-ShareAlike 2.5 License
98
     *    http://creativecommons.org/licenses/by-sa/2.5/
99
     */
100
    public static function is_valid_address($address)
101
    {
102
        return \Swift_Validate::email($address);
103
    }
104
105
    /**
106
     * Get send_all_emails_to
107
     *
108
     * @return array Keys are addresses, values are names
109
     */
110
    public static function getSendAllEmailsTo()
111
    {
112
        return static::mergeConfiguredEmails('send_all_emails_to', 'SS_SEND_ALL_EMAILS_TO');
113
    }
114
115
    /**
116
     * Get cc_all_emails_to
117
     *
118
     * @return array
119
     */
120
    public static function getCCAllEmailsTo()
121
    {
122
        return static::mergeConfiguredEmails('cc_all_emails_to', 'SS_CC_ALL_EMAILS_TO');
123
    }
124
125
    /**
126
     * Get bcc_all_emails_to
127
     *
128
     * @return array
129
     */
130
    public static function getBCCAllEmailsTo()
131
    {
132
        return static::mergeConfiguredEmails('bcc_all_emails_to', 'SS_BCC_ALL_EMAILS_TO');
133
    }
134
135
    /**
136
     * Get send_all_emails_from
137
     *
138
     * @return array
139
     */
140
    public static function getSendAllEmailsFrom()
141
    {
142
        return static::mergeConfiguredEmails('send_all_emails_from', 'SS_SEND_ALL_EMAILS_FROM');
143
    }
144
145
    /**
146
     * Normalise email list from config merged with env vars
147
     *
148
     * @param string $config Config key
149
     * @param string $env Env variable key
150
     * @return array Array of email addresses
151
     */
152
    protected static function mergeConfiguredEmails($config, $env)
153
    {
154
        // Normalise config list
155
        $normalised = [];
156
        $source = (array)static::config()->get($config);
157
        foreach ($source as $address => $name) {
158
            if ($address && !is_numeric($address)) {
159
                $normalised[$address] = $name;
160
            } elseif ($name) {
161
                $normalised[$name] = null;
162
            }
163
        }
164
        $extra = Environment::getEnv($env);
165
        if ($extra) {
166
            $normalised[$extra] = null;
167
        }
168
        return $normalised;
169
    }
170
171
    /**
172
     * Encode an email-address to protect it from spambots.
173
     * At the moment only simple string substitutions,
174
     * which are not 100% safe from email harvesting.
175
     *
176
     * @param string $email Email-address
177
     * @param string $method Method for obfuscating/encoding the address
178
     *    - 'direction': Reverse the text and then use CSS to put the text direction back to normal
179
     *    - 'visible': Simple string substitution ('@' to '[at]', '.' to '[dot], '-' to [dash])
180
     *    - 'hex': Hexadecimal URL-Encoding - useful for mailto: links
181
     * @return string
182
     */
183
    public static function obfuscate($email, $method = 'visible')
184
    {
185
        switch ($method) {
186
            case 'direction':
187
                Requirements::customCSS('span.codedirection { unicode-bidi: bidi-override; direction: rtl; }', 'codedirectionCSS');
188
189
                return '<span class="codedirection">' . strrev($email) . '</span>';
190
            case 'visible':
191
                $obfuscated = ['@' => ' [at] ', '.' => ' [dot] ', '-' => ' [dash] '];
192
193
                return strtr($email, $obfuscated);
194
            case 'hex':
195
                $encoded = '';
196
                $emailLength = strlen($email);
197
                for ($x = 0; $x < $emailLength; $x++) {
198
                    $encoded .= '&#x' . bin2hex($email[$x]) . ';';
199
                }
200
201
                return $encoded;
202
            default:
203
                user_error('Email::obfuscate(): Unknown obfuscation method', E_USER_NOTICE);
204
205
                return $email;
206
        }
207
    }
208
209
    /**
210
     * Email constructor.
211
     * @param string|array|null $from
212
     * @param string|array|null $to
213
     * @param string|null $subject
214
     * @param string|null $body
215
     * @param string|array|null $cc
216
     * @param string|array|null $bcc
217
     * @param string|null $returnPath
218
     */
219
    public function __construct(
220
        $from = null,
221
        $to = null,
222
        $subject = null,
223
        $body = null,
224
        $cc = null,
225
        $bcc = null,
226
        $returnPath = null
227
    ) {
228
        if ($from) {
229
            $this->setFrom($from);
230
        }
231
        if ($to) {
232
            $this->setTo($to);
233
        }
234
        if ($subject) {
235
            $this->setSubject($subject);
236
        }
237
        if ($body) {
238
            $this->setBody($body);
239
        }
240
        if ($cc) {
241
            $this->setCC($cc);
242
        }
243
        if ($bcc) {
244
            $this->setBCC($bcc);
245
        }
246
        if ($returnPath) {
247
            $this->setReturnPath($returnPath);
248
        }
249
250
        parent::__construct();
251
    }
252
253
    /**
254
     * @return Swift_Message
255
     */
256
    public function getSwiftMessage()
257
    {
258
        if (!$this->swiftMessage) {
259
            $this->setSwiftMessage(new Swift_Message(null, null, 'text/html', 'utf-8'));
260
        }
261
262
        return $this->swiftMessage;
263
    }
264
265
    /**
266
     * @param Swift_Message $swiftMessage
267
     *
268
     * @return $this
269
     */
270
    public function setSwiftMessage($swiftMessage)
271
    {
272
        $swiftMessage->setDate(DBDatetime::now()->getTimestamp());
273
        if (!$swiftMessage->getFrom() && ($defaultFrom = $this->config()->get('admin_email'))) {
274
            $swiftMessage->setFrom($defaultFrom);
275
        }
276
        $this->swiftMessage = $swiftMessage;
277
278
        return $this;
279
    }
280
281
    /**
282
     * @return string[]
283
     */
284
    public function getFrom()
285
    {
286
        return $this->getSwiftMessage()->getFrom();
287
    }
288
289
    /**
290
     * @param string|array $address
291
     * @param string|null $name
292
     * @return $this
293
     */
294
    public function setFrom($address, $name = null)
295
    {
296
        $this->getSwiftMessage()->setFrom($address, $name);
297
298
        return $this;
299
    }
300
301
    /**
302
     * @param string|array $address
303
     * @param string|null $name
304
     * @return $this
305
     */
306
    public function addFrom($address, $name = null)
307
    {
308
        $this->getSwiftMessage()->addFrom($address, $name);
0 ignored issues
show
Bug introduced by
It seems like $address can also be of type array; however, parameter $address of Swift_Mime_SimpleMessage::addFrom() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

308
        $this->getSwiftMessage()->addFrom(/** @scrutinizer ignore-type */ $address, $name);
Loading history...
309
310
        return $this;
311
    }
312
313
    /**
314
     * @return string
315
     */
316
    public function getSender()
317
    {
318
        return $this->getSwiftMessage()->getSender();
319
    }
320
321
    /**
322
     * @param string $address
323
     * @param string|null $name
324
     * @return $this
325
     */
326
    public function setSender($address, $name = null)
327
    {
328
        $this->getSwiftMessage()->setSender($address, $name);
329
330
        return $this;
331
    }
332
333
    /**
334
     * @return string
335
     */
336
    public function getReturnPath()
337
    {
338
        return $this->getSwiftMessage()->getReturnPath();
339
    }
340
341
    /**
342
     * The bounce handler address
343
     *
344
     * @param string $address Email address where bounce notifications should be sent
345
     * @return $this
346
     */
347
    public function setReturnPath($address)
348
    {
349
        $this->getSwiftMessage()->setReturnPath($address);
350
        return $this;
351
    }
352
353
    /**
354
     * @return array
355
     */
356
    public function getTo()
357
    {
358
        return $this->getSwiftMessage()->getTo();
359
    }
360
361
    /**
362
     * Set recipient(s) of the email
363
     *
364
     * To send to many, pass an array:
365
     * ['[email protected]' => 'My Name', '[email protected]'];
366
     *
367
     * @param string|array $address The message recipient(s) - if sending to multiple, use an array of address => name
368
     * @param string|null $name The name of the recipient (if one)
369
     * @return $this
370
     */
371
    public function setTo($address, $name = null)
372
    {
373
        $this->getSwiftMessage()->setTo($address, $name);
374
375
        return $this;
376
    }
377
378
    /**
379
     * @param string|array $address
380
     * @param string|null $name
381
     * @return $this
382
     */
383
    public function addTo($address, $name = null)
384
    {
385
        $this->getSwiftMessage()->addTo($address, $name);
0 ignored issues
show
Bug introduced by
It seems like $address can also be of type array; however, parameter $address of Swift_Mime_SimpleMessage::addTo() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

385
        $this->getSwiftMessage()->addTo(/** @scrutinizer ignore-type */ $address, $name);
Loading history...
386
387
        return $this;
388
    }
389
390
    /**
391
     * @return array
392
     */
393
    public function getCC()
394
    {
395
        return $this->getSwiftMessage()->getCc();
396
    }
397
398
    /**
399
     * @param string|array $address
400
     * @param string|null $name
401
     * @return $this
402
     */
403
    public function setCC($address, $name = null)
404
    {
405
        $this->getSwiftMessage()->setCc($address, $name);
406
407
        return $this;
408
    }
409
410
    /**
411
     * @param string|array $address
412
     * @param string|null $name
413
     * @return $this
414
     */
415
    public function addCC($address, $name = null)
416
    {
417
        $this->getSwiftMessage()->addCc($address, $name);
0 ignored issues
show
Bug introduced by
It seems like $address can also be of type array; however, parameter $address of Swift_Mime_SimpleMessage::addCc() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

417
        $this->getSwiftMessage()->addCc(/** @scrutinizer ignore-type */ $address, $name);
Loading history...
418
419
        return $this;
420
    }
421
422
    /**
423
     * @return array
424
     */
425
    public function getBCC()
426
    {
427
        return $this->getSwiftMessage()->getBcc();
428
    }
429
430
    /**
431
     * @param string|array $address
432
     * @param string|null $name
433
     * @return $this
434
     */
435
    public function setBCC($address, $name = null)
436
    {
437
        $this->getSwiftMessage()->setBcc($address, $name);
438
439
        return $this;
440
    }
441
442
    /**
443
     * @param string|array $address
444
     * @param string|null $name
445
     * @return $this
446
     */
447
    public function addBCC($address, $name = null)
448
    {
449
        $this->getSwiftMessage()->addBcc($address, $name);
0 ignored issues
show
Bug introduced by
It seems like $address can also be of type array; however, parameter $address of Swift_Mime_SimpleMessage::addBcc() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

449
        $this->getSwiftMessage()->addBcc(/** @scrutinizer ignore-type */ $address, $name);
Loading history...
450
451
        return $this;
452
    }
453
454
    public function getReplyTo()
455
    {
456
        return $this->getSwiftMessage()->getReplyTo();
457
    }
458
459
    /**
460
     * @param string|array $address
461
     * @param string|null $name
462
     * @return $this
463
     */
464
    public function setReplyTo($address, $name = null)
465
    {
466
        $this->getSwiftMessage()->setReplyTo($address, $name);
467
468
        return $this;
469
    }
470
471
    /**
472
     * @param string|array $address
473
     * @param string|null $name
474
     * @return $this
475
     */
476
    public function addReplyTo($address, $name = null)
477
    {
478
        $this->getSwiftMessage()->addReplyTo($address, $name);
0 ignored issues
show
Bug introduced by
It seems like $address can also be of type array; however, parameter $address of Swift_Mime_SimpleMessage::addReplyTo() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

478
        $this->getSwiftMessage()->addReplyTo(/** @scrutinizer ignore-type */ $address, $name);
Loading history...
479
480
        return $this;
481
    }
482
483
    /**
484
     * @return string
485
     */
486
    public function getSubject()
487
    {
488
        return $this->getSwiftMessage()->getSubject();
489
    }
490
491
    /**
492
     * @param string $subject The Subject line for the email
493
     * @return $this
494
     */
495
    public function setSubject($subject)
496
    {
497
        $this->getSwiftMessage()->setSubject($subject);
498
499
        return $this;
500
    }
501
502
    /**
503
     * @return int
504
     */
505
    public function getPriority()
506
    {
507
        return $this->getSwiftMessage()->getPriority();
508
    }
509
510
    /**
511
     * @param int $priority
512
     * @return $this
513
     */
514
    public function setPriority($priority)
515
    {
516
        $this->getSwiftMessage()->setPriority($priority);
517
518
        return $this;
519
    }
520
521
    /**
522
     * @param string $path Path to file
523
     * @param string $alias An override for the name of the file
524
     * @param string $mime The mime type for the attachment
525
     * @return $this
526
     */
527
    public function addAttachment($path, $alias = null, $mime = null)
528
    {
529
        $attachment = \Swift_Attachment::fromPath($path);
530
        if ($alias) {
531
            $attachment->setFilename($alias);
532
        }
533
        if ($mime) {
534
            $attachment->setContentType($mime);
535
        }
536
        $this->getSwiftMessage()->attach($attachment);
537
538
        return $this;
539
    }
540
541
    /**
542
     * @param string $data
543
     * @param string $name
544
     * @param string $mime
545
     * @return $this
546
     */
547
    public function addAttachmentFromData($data, $name, $mime = null)
548
    {
549
        $attachment = new \Swift_Attachment($data, $name);
550
        if ($mime) {
551
            $attachment->setContentType($mime);
552
        }
553
        $this->getSwiftMessage()->attach($attachment);
554
555
        return $this;
556
    }
557
558
    /**
559
     * @return array|ViewableData The template data
560
     */
561
    public function getData()
562
    {
563
        return $this->data;
564
    }
565
566
    /**
567
     * @param array|ViewableData $data The template data to set
568
     * @return $this
569
     */
570
    public function setData($data)
571
    {
572
        $this->data = $data;
573
        $this->invalidateBody();
574
575
        return $this;
576
    }
577
578
    /**
579
     * @param string|array $name The data name to add or array to names => value
580
     * @param string|null $value The value of the data to add
581
     * @return $this
582
     */
583
    public function addData($name, $value = null)
584
    {
585
        if (is_array($name)) {
586
            $this->data = array_merge($this->data, $name);
0 ignored issues
show
Bug introduced by
It seems like $this->data can also be of type SilverStripe\View\ViewableData; however, parameter $arrays of array_merge() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

586
            $this->data = array_merge(/** @scrutinizer ignore-type */ $this->data, $name);
Loading history...
587
        } elseif (is_array($this->data)) {
588
            $this->data[$name] = $value;
589
        } else {
590
            $this->data->$name = $value;
591
        }
592
593
        $this->invalidateBody();
594
595
        return $this;
596
    }
597
598
    /**
599
     * Remove a datum from the message
600
     *
601
     * @param string $name
602
     * @return $this
603
     */
604
    public function removeData($name)
605
    {
606
        if (is_array($this->data)) {
607
            unset($this->data[$name]);
608
        } else {
609
            $this->data->$name = null;
610
        }
611
612
        $this->invalidateBody();
613
        
614
        return $this;
615
    }
616
617
    /**
618
     * @return string
619
     */
620
    public function getBody()
621
    {
622
        return $this->getSwiftMessage()->getBody();
623
    }
624
625
    /**
626
     * @param string $body The email body
627
     * @return $this
628
     */
629
    public function setBody($body)
630
    {
631
        $plainPart = $this->findPlainPart();
632
        if ($plainPart) {
633
            $this->getSwiftMessage()->detach($plainPart);
634
        }
635
        unset($plainPart);
636
637
        $body = HTTP::absoluteURLs($body);
638
        $this->getSwiftMessage()->setBody($body);
639
640
        return $this;
641
    }
642
643
    /**
644
     * @return $this
645
     */
646
    public function invalidateBody()
647
    {
648
        $this->setBody(null);
649
650
        return $this;
651
    }
652
653
    /**
654
     * @return string The base URL for the email
655
     */
656
    public function BaseURL()
657
    {
658
        return Director::absoluteBaseURL();
659
    }
660
661
    /**
662
     * Debugging help
663
     *
664
     * @return string Debug info
665
     */
666
    public function debug()
667
    {
668
        $this->render();
669
670
        $class = static::class;
671
        return "<h2>Email template {$class}:</h2>\n" . '<pre>' . $this->getSwiftMessage()->toString() . '</pre>';
672
    }
673
674
    /**
675
     * @return string
676
     */
677
    public function getHTMLTemplate()
678
    {
679
        if ($this->HTMLTemplate) {
680
            return $this->HTMLTemplate;
681
        }
682
683
        return ThemeResourceLoader::inst()->findTemplate(
684
            SSViewer::get_templates_by_class(static::class, '', self::class),
685
            SSViewer::get_themes()
686
        );
687
    }
688
689
    /**
690
     * Set the template to render the email with
691
     *
692
     * @param string $template
693
     * @return $this
694
     */
695
    public function setHTMLTemplate($template)
696
    {
697
        if (substr($template, -3) == '.ss') {
698
            $template = substr($template, 0, -3);
699
        }
700
        $this->HTMLTemplate = $template;
701
702
        return $this;
703
    }
704
705
    /**
706
     * Get the template to render the plain part with
707
     *
708
     * @return string
709
     */
710
    public function getPlainTemplate()
711
    {
712
        return $this->plainTemplate;
713
    }
714
715
    /**
716
     * Set the template to render the plain part with
717
     *
718
     * @param string $template
719
     * @return $this
720
     */
721
    public function setPlainTemplate($template)
722
    {
723
        if (substr($template, -3) == '.ss') {
724
            $template = substr($template, 0, -3);
725
        }
726
        $this->plainTemplate = $template;
727
728
        return $this;
729
    }
730
731
    /**
732
     * @param array $recipients
733
     * @return $this
734
     */
735
    public function setFailedRecipients($recipients)
736
    {
737
        $this->failedRecipients = $recipients;
738
739
        return $this;
740
    }
741
742
    /**
743
     * @return array
744
     */
745
    public function getFailedRecipients()
746
    {
747
        return $this->failedRecipients;
748
    }
749
750
    /**
751
     * Used by {@link SSViewer} templates to detect if we're rendering an email template rather than a page template
752
     *
753
     * @return bool
754
     */
755
    public function IsEmail()
756
    {
757
        return true;
758
    }
759
760
    /**
761
     * Send the message to the recipients
762
     *
763
     * @return bool true if successful or array of failed recipients
764
     */
765
    public function send()
766
    {
767
        if (!$this->getBody()) {
768
            $this->render();
769
        }
770
        if (!$this->hasPlainPart()) {
771
            $this->generatePlainPartFromBody();
772
        }
773
        return Injector::inst()->get(Mailer::class)->send($this);
774
    }
775
776
    /**
777
     * @return array|bool
778
     */
779
    public function sendPlain()
780
    {
781
        if (!$this->hasPlainPart()) {
782
            $this->render(true);
783
        }
784
        return Injector::inst()->get(Mailer::class)->send($this);
785
    }
786
787
    /**
788
     * Render the email
789
     * @param bool $plainOnly Only render the message as plain text
790
     * @return $this
791
     */
792
    public function render($plainOnly = false)
793
    {
794
        if ($existingPlainPart = $this->findPlainPart()) {
795
            $this->getSwiftMessage()->detach($existingPlainPart);
796
        }
797
        unset($existingPlainPart);
798
799
        // Respect explicitly set body
800
        $htmlPart = $plainOnly ? null : $this->getBody();
801
        $plainPart = $plainOnly ? $this->getBody() : null;
802
803
        // Ensure we can at least render something
804
        $htmlTemplate = $this->getHTMLTemplate();
805
        $plainTemplate = $this->getPlainTemplate();
806
        if (!$htmlTemplate && !$plainTemplate && !$plainPart && !$htmlPart) {
807
            return $this;
808
        }
809
810
        // Do not interfere with emails styles
811
        Requirements::clear();
812
813
        // Render plain part
814
        if ($plainTemplate && !$plainPart) {
815
            $plainPart = $this->renderWith($plainTemplate, $this->getData())->Plain();
0 ignored issues
show
Bug introduced by
It seems like $this->getData() can also be of type SilverStripe\View\ViewableData; however, parameter $customFields of SilverStripe\View\ViewableData::renderWith() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

815
            $plainPart = $this->renderWith($plainTemplate, /** @scrutinizer ignore-type */ $this->getData())->Plain();
Loading history...
816
        }
817
818
        // Render HTML part, either if sending html email, or a plain part is lacking
819
        if (!$htmlPart && $htmlTemplate && (!$plainOnly || empty($plainPart))) {
820
            $htmlPart = $this->renderWith($htmlTemplate, $this->getData());
821
        }
822
823
        // Plain part fails over to generated from html
824
        if (!$plainPart && $htmlPart) {
825
            /** @var DBHTMLText $htmlPartObject */
826
            $htmlPartObject = DBField::create_field('HTMLFragment', $htmlPart);
827
            $plainPart = $htmlPartObject->Plain();
828
        }
829
830
        // Rendering is finished
831
        Requirements::restore();
832
833
        // Fail if no email to send
834
        if (!$plainPart && !$htmlPart) {
835
            return $this;
836
        }
837
838
        // Build HTML / Plain components
839
        if ($htmlPart && !$plainOnly) {
840
            $this->setBody($htmlPart);
841
            $this->getSwiftMessage()->setContentType('text/html');
842
            $this->getSwiftMessage()->setCharset('utf-8');
843
            if ($plainPart) {
844
                $this->getSwiftMessage()->addPart($plainPart, 'text/plain', 'utf-8');
845
            }
846
        } else {
847
            if ($plainPart) {
848
                $this->setBody($plainPart);
849
            }
850
            $this->getSwiftMessage()->setContentType('text/plain');
851
            $this->getSwiftMessage()->setCharset('utf-8');
852
        }
853
854
        return $this;
855
    }
856
857
    /**
858
     * @return Swift_MimePart|false
859
     */
860
    public function findPlainPart()
861
    {
862
        foreach ($this->getSwiftMessage()->getChildren() as $child) {
863
            if ($child instanceof Swift_MimePart && $child->getContentType() == 'text/plain') {
864
                return $child;
865
            }
866
        }
867
        return false;
868
    }
869
870
    /**
871
     * @return bool
872
     */
873
    public function hasPlainPart()
874
    {
875
        if ($this->getSwiftMessage()->getContentType() === 'text/plain') {
876
            return true;
877
        }
878
        return (bool) $this->findPlainPart();
879
    }
880
881
    /**
882
     * Automatically adds a plain part to the email generated from the current Body
883
     *
884
     * @return $this
885
     */
886
    public function generatePlainPartFromBody()
887
    {
888
        $plainPart = $this->findPlainPart();
889
        if ($plainPart) {
890
            $this->getSwiftMessage()->detach($plainPart);
891
        }
892
        unset($plainPart);
893
894
        $this->getSwiftMessage()->addPart(
895
            Convert::xml2raw($this->getBody()),
896
            'text/plain',
897
            'utf-8'
898
        );
899
900
        return $this;
901
    }
902
}
903