Issues (23)

src/InboundEmail.php (1 issue)

1
<?php
2
3
namespace BeyondCode\Mailbox;
4
5
use Carbon\Carbon;
6
use EmailReplyParser\EmailReplyParser;
7
use Illuminate\Contracts\Mail\Mailable;
8
use Illuminate\Database\Eloquent\Model;
9
use Illuminate\Support\Collection;
10
use Illuminate\Support\Facades\Mail;
11
use Illuminate\Support\Str;
12
use ZBateson\MailMimeParser\Header\AddressHeader;
13
use ZBateson\MailMimeParser\Header\Part\AddressPart;
14
use ZBateson\MailMimeParser\Message as MimeMessage;
15
use ZBateson\MailMimeParser\Message\Part\MessagePart;
16
17
class InboundEmail extends Model
18
{
19
    protected $table = 'mailbox_inbound_emails';
20
21
    /** @var MimeMessage */
22
    protected $mimeMessage;
23
24
    protected $fillable = [
25
        'message',
26
    ];
27
28
    protected static function boot()
29
    {
30
        parent::boot();
31
32
        static::creating(function ($model) {
33
            $model->message_id = $model->id();
34
        });
35
    }
36
37
    public static function fromMessage($message)
38
    {
39
        return new static([
40
            'message' => $message,
41
        ]);
42
    }
43
44
    public function id(): string
45
    {
46
        return $this->message()->getHeaderValue('Message-Id', Str::random());
47
    }
48
49
    public function date(): Carbon
50
    {
51
        return Carbon::make($this->message()->getHeaderValue('Date'));
52
    }
53
54
    public function text(): ?string
55
    {
56
        return $this->message()->getTextContent();
57
    }
58
59
    public function visibleText(): ?string
60
    {
61
        return EmailReplyParser::parseReply($this->text());
62
    }
63
64
    public function html(): ?string
65
    {
66
        return $this->message()->getHtmlContent();
67
    }
68
69
    public function headerValue($headerName): ?string
70
    {
71
        return $this->message()->getHeaderValue($headerName, null);
72
    }
73
74
    public function subject(): ?string
75
    {
76
        return $this->message()->getHeaderValue('Subject');
77
    }
78
79
    public function from(): string
80
    {
81
        $from = $this->message()->getHeader('From');
82
83
        if ($from instanceof AddressHeader) {
84
            return $from->getEmail();
85
        }
86
87
        return '';
88
    }
89
90
    public function fromName(): string
91
    {
92
        $from = $this->message()->getHeader('From');
93
94
        if ($from instanceof AddressHeader) {
95
            return $from->getPersonName();
96
        }
97
98
        return '';
99
    }
100
101
    /**
102
     * @return AddressPart[]
103
     */
104
    public function to(): array
105
    {
106
        return $this->convertAddressHeader($this->message()->getHeader('To'));
107
    }
108
109
    /**
110
     * @return AddressPart[]
111
     */
112
    public function cc(): array
113
    {
114
        return $this->convertAddressHeader($this->message()->getHeader('Cc'));
115
    }
116
117
    /**
118
     * @return AddressPart[]
119
     */
120
    public function bcc(): array
121
    {
122
        return $this->convertAddressHeader($this->message()->getHeader('Bcc'));
123
    }
124
125
    protected function convertAddressHeader($header): array
126
    {
127
        if ($header instanceof AddressHeader) {
128
            return Collection::make($header->getAddresses())->toArray();
0 ignored issues
show
$header->getAddresses() of type ZBateson\MailMimeParser\Header\Part\AddressPart[] is incompatible with the type Illuminate\Contracts\Support\Arrayable expected by parameter $items of Illuminate\Support\Collection::make(). ( Ignorable by Annotation )

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

128
            return Collection::make(/** @scrutinizer ignore-type */ $header->getAddresses())->toArray();
Loading history...
129
        }
130
131
        return [];
132
    }
133
134
    /**
135
     * @return MessagePart[]
136
     */
137
    public function attachments()
138
    {
139
        return $this->message()->getAllAttachmentParts();
140
    }
141
142
    public function message(): MimeMessage
143
    {
144
        $this->mimeMessage = $this->mimeMessage ?: MimeMessage::from($this->message, true);
145
146
        return $this->mimeMessage;
147
    }
148
149
    public function reply(Mailable $mailable)
150
    {
151
        if ($mailable instanceof \Illuminate\Mail\Mailable) {
152
            $usesSymfonyMailer = version_compare(app()->version(), '9.0.0', '>');
153
154
            if ($usesSymfonyMailer) {
155
                $mailable->withSymfonyMessage(function (\Symfony\Component\Mime\Email $email) {
156
                    $email->getHeaders()->addIdHeader('In-Reply-To', $this->id());
157
                });
158
            } else {
159
                $mailable->withSwiftMessage(function (\Swift_Message $message) {
160
                    $message->getHeaders()->addIdHeader('In-Reply-To', $this->id());
161
                });
162
            }
163
        }
164
165
        return Mail::to($this->headerValue('Reply-To') ?: $this->from())->send($mailable);
166
    }
167
168
    public function forward($recipients)
169
    {
170
        return Mail::send([], [], function ($message) use ($recipients) {
171
            $message->to($recipients)
172
                ->subject($this->subject())
173
                ->setBody($this->body(), $this->message()->getContentType());
174
        });
175
    }
176
177
    public function body(): ?string
178
    {
179
        return $this->isHtml() ? $this->html() : $this->text();
180
    }
181
182
    public function isHtml(): bool
183
    {
184
        return ! empty($this->html());
185
    }
186
187
    public function isText(): bool
188
    {
189
        return ! empty($this->text());
190
    }
191
192
    public function isValid(): bool
193
    {
194
        return $this->from() !== '' && ($this->isText() || $this->isHtml());
195
    }
196
197
    public function isAutoReply($checkCommonSubjects = true): bool
198
    {
199
        if ($this->headerValue('x-autorespond')) {
200
            return true;
201
        }
202
203
        if (in_array($this->headerValue('precedence'), ['auto_reply', 'bulk', 'junk'])) {
204
            return true;
205
        }
206
207
        if (in_array($this->headerValue('x-precedence'), ['auto_reply', 'bulk', 'junk'])) {
208
            return true;
209
        }
210
        if (in_array($this->headerValue('auto-submitted'), ['auto-replied', 'auto-generated'])) {
211
            return true;
212
        }
213
214
        if ($checkCommonSubjects) {
215
            return Str::startsWith($this->subject(), [
216
                'Auto:',
217
                'Automatic reply',
218
                'Autosvar',
219
                'Automatisk svar',
220
                'Automatisch antwoord',
221
                'Abwesenheitsnotiz',
222
                'Risposta Non al computer',
223
                'Automatisch antwoord',
224
                'Auto Response',
225
                'Respuesta automática',
226
                'Fuori sede',
227
                'Out of Office',
228
                'Frånvaro',
229
                'Réponse automatique',
230
            ]);
231
        }
232
233
        return false;
234
    }
235
}
236