xref: /plugin/smtp/vendor/txthinking/mailer/src/Mailer/Message.php (revision 28d0809a4424b7a71eb621f24d1b3a19c5927170)
1<?php
2/***************************************************\
3 *
4 *  Mailer (https://github.com/txthinking/Mailer)
5 *
6 *  A lightweight PHP SMTP mail sender.
7 *  Implement RFC0821, RFC0822, RFC1869, RFC2045, RFC2821
8 *
9 *  Support html body, don't worry that the receiver's
10 *  mail client can't support html, because Mailer will
11 *  send both text/plain and text/html body, so if the
12 *  mail client can't support html, it will display the
13 *  text/plain body.
14 *
15 *  Create Date 2012-07-25.
16 *  Under the MIT license.
17 *
18 \***************************************************/
19namespace Tx\Mailer;
20
21class Message
22{
23    /**
24     * from name
25     */
26    protected $fromName;
27
28    /**
29     * from email
30     */
31    protected $fromEmail;
32
33    /**
34     * fake from name
35     */
36    protected $fakeFromName;
37
38    /**
39     * fake from email
40     */
41    protected $fakeFromEmail;
42
43    /**
44     * to email
45     */
46    protected $to = array();
47
48    /**
49     * cc email
50     */
51    protected $cc = array();
52
53    /**
54     * bcc email
55     */
56    protected $bcc = array();
57
58    /**
59     * mail subject
60     */
61    protected $subject;
62
63    /**
64     * mail body
65     */
66    protected $body;
67
68    /**
69     *mail attachment
70     */
71    protected $attachment = array();
72
73    /**
74     * message header
75     */
76    protected $header = array();
77
78    /**
79     * charset
80     */
81    protected $charset = "UTF-8";
82
83    /**
84     * header multipart boundaryMixed
85     */
86    protected $boundaryMixed;
87
88    /**
89     * header multipart alternative
90     */
91    protected $boundaryAlternative;
92
93    /**
94     * $this->CRLF
95     * @var string
96     */
97    protected $CRLF = "\r\n";
98
99
100    /**
101     * Address for the reply-to header
102     * @var string
103     */
104    protected $replyToName;
105
106    /**
107     * Address for the reply-to header
108     * @var string
109     */
110    protected $replyToEmail;
111
112
113    public function setReplyTo($name, $email)
114    {
115        $this->replyToName = $name;
116        $this->replyToEmail = $email;
117        return $this;
118    }
119
120
121    /**
122     * set mail from
123     * @param string $name
124     * @param string $email
125     * @return $this
126     */
127    public function setFrom($name, $email)
128    {
129        $this->fromName = $name;
130        $this->fromEmail = $email;
131        return $this;
132    }
133
134
135    /**
136     * set mail fake from
137     * @param string $name
138     * @param string $email
139     * @return $this
140     */
141    public function setFakeFrom($name, $email)
142    {
143        $this->fakeFromName = $name;
144        $this->fakeFromEmail = $email;
145        return $this;
146    }
147
148    /**
149     * add mail receiver
150     * @param string $name
151     * @param string $email
152     * @return $this
153     */
154    public function addTo($name, $email)
155    {
156        $this->to[$email] = $name;
157        return $this;
158    }
159
160    /**
161     * add cc mail receiver
162     * @param string $name
163     * @param string $email
164     * @return $this
165     */
166    public function addCc($name, $email)
167    {
168        $this->cc[$email] = $name;
169        return $this;
170    }
171
172    /**
173     * add bcc mail receiver
174     * @param string $name
175     * @param string $email
176     * @return $this
177     */
178    public function addBcc($name, $email)
179    {
180        $this->bcc[$email] = $name;
181        return $this;
182    }
183
184    /**
185     * set mail subject
186     * @param string $subject
187     * @return $this
188     */
189    public function setSubject($subject)
190    {
191        $this->subject = $subject;
192        return $this;
193    }
194
195    /**
196     * set mail body
197     * @param string $body
198     * @return $this
199     */
200    public function setBody($body)
201    {
202        $this->body = $body;
203        return $this;
204    }
205
206    /**
207     * add mail attachment
208     * @param $name
209     * @param $path
210     * @return $this
211     */
212    public function addAttachment($name, $path)
213    {
214        $this->attachment[$name] = $path;
215        return $this;
216    }
217
218    /**
219     * @return string
220     */
221    public function getFromName()
222    {
223        return $this->fromName;
224    }
225
226    /**
227     * @return string
228     */
229    public function getFromEmail()
230    {
231        return $this->fromEmail;
232    }
233
234
235    /**
236     * @return string
237     */
238    public function getFakeFromName()
239    {
240        return $this->fakeFromName;
241    }
242
243    /**
244     * @return string
245     */
246    public function getFakeFromEmail()
247    {
248        return $this->fakeFromEmail;
249    }
250
251    /**
252     * @return mixed
253     */
254    public function getTo()
255    {
256        return $this->to;
257    }
258
259    /**
260     * @return mixed
261     */
262    public function getCc()
263    {
264        return $this->cc;
265    }
266
267    /**
268     * @return mixed
269     */
270    public function getBcc()
271    {
272        return $this->bcc;
273    }
274
275    /**
276     * @return mixed
277     */
278    public function getSubject()
279    {
280        return $this->subject;
281    }
282
283    /**
284     * @return mixed
285     */
286    public function getBody()
287    {
288        return $this->body;
289    }
290
291    /**
292     * @return array
293     */
294    public function getAttachment()
295    {
296        return $this->attachment;
297    }
298
299    /**
300     * Create mail header
301     * @return $this
302     */
303    protected function createHeader()
304    {
305        $this->header['Date'] = date('r');
306
307        $fromName = "";
308        $fromEmail = $this->fromEmail;
309        if(!empty($this->fromName)){
310            $fromName = sprintf("=?utf-8?B?%s?= ", base64_encode($this->fromName));
311        }
312        if(!empty($this->fakeFromEmail)){
313            if(!empty($this->fakeFromName)){
314                $fromName = sprintf("=?utf-8?B?%s?= ", base64_encode($this->fakeFromName));
315            }
316            $fromEmail = $this->fakeFromEmail;
317        }
318        $this->header['Return-Path'] = $fromEmail;
319        $this->header['From'] = $fromName . "<" . $fromEmail .">";
320
321        $this->header['To'] = '';
322        foreach ($this->to as $toEmail => $toName) {
323            if(!empty($toName)){
324                $toName = sprintf("=?utf-8?B?%s?= ", base64_encode($toName));
325            }
326            $this->header['To'] .= $toName . "<" . $toEmail . ">, ";
327        }
328        $this->header['To'] = substr($this->header['To'], 0, -2);
329        $this->header['Cc'] = '';
330        foreach ($this->cc as $toEmail => $toName) {
331            if(!empty($toName)){
332                $toName = sprintf("=?utf-8?B?%s?= ", base64_encode($toName));
333            }
334            $this->header['Cc'] .= $toName . "<" . $toEmail . ">, ";
335        }
336        $this->header['Cc'] = substr($this->header['Cc'], 0, -2);
337        $this->header['Bcc'] = '';
338        foreach ($this->bcc as $toEmail => $toName) {
339            if(!empty($toName)){
340                $toName = sprintf("=?utf-8?B?%s?= ", base64_encode($toName));
341            }
342            $this->header['Bcc'] .= $toName . "<" . $toEmail . ">, ";
343        }
344        $this->header['Bcc'] = substr($this->header['Bcc'], 0, -2);
345
346        $replyToName = "";
347        if(!empty($this->replyToEmail)){
348            if(!empty($this->replyToName)){
349                $replyToName = sprintf("=?utf-8?B?%s?= ", base64_encode($this->replyToName));
350            }
351            $this->header['Reply-To'] = $replyToName . "<" . $this->replyToEmail . ">";
352        }
353
354        if(empty($this->subject)){
355            $subject = '';
356        }else{
357            $subject = sprintf("=?utf-8?B?%s?= ", base64_encode($this->subject));
358        }
359        $this->header['Subject'] = $subject;
360
361        $this->header['Message-ID'] = '<' . md5(uniqid()) . $this->fromEmail . '>';
362        $this->header['X-Priority'] = '3';
363        $this->header['X-Mailer'] = 'Mailer (https://github.com/txthinking/Mailer)';
364        $this->header['MIME-Version'] = '1.0';
365        if (!empty($this->attachment)){
366            $this->boundaryMixed = md5(md5(time().'TxMailer').uniqid());
367            $this->header['Content-Type'] = "multipart/mixed; \r\n\tboundary=\"" . $this->boundaryMixed . "\"";
368        }
369        $this->boundaryAlternative = md5(md5(time().'TXMailer').uniqid());
370        return $this;
371    }
372
373    /**
374     * @brief createBody create body
375     *
376     * @return string
377     */
378    protected function createBody()
379    {
380        $in = "";
381        $in .= "Content-Type: multipart/alternative; boundary=\"$this->boundaryAlternative\"" . $this->CRLF;
382        $in .= $this->CRLF;
383        $in .= "--" . $this->boundaryAlternative . $this->CRLF;
384        $in .= "Content-Type: text/plain; charset=\"" . $this->charset . "\"" . $this->CRLF;
385        $in .= "Content-Transfer-Encoding: base64" . $this->CRLF;
386        $in .= $this->CRLF;
387        $in .= chunk_split(base64_encode($this->body)) . $this->CRLF;
388        $in .= $this->CRLF;
389        $in .= "--" . $this->boundaryAlternative . $this->CRLF;
390        $in .= "Content-Type: text/html; charset=\"" . $this->charset ."\"" . $this->CRLF;
391        $in .= "Content-Transfer-Encoding: base64" . $this->CRLF;
392        $in .= $this->CRLF;
393        $in .= chunk_split(base64_encode($this->body)) . $this->CRLF;
394        $in .= $this->CRLF;
395        $in .= "--" . $this->boundaryAlternative . "--" . $this->CRLF;
396        return $in;
397    }
398
399    /**
400     * @brief createBodyWithAttachment create body with attachment
401     *
402     * @return string
403     */
404    protected function createBodyWithAttachment()
405    {
406        $in = "";
407        $in .= $this->CRLF;
408        $in .= $this->CRLF;
409        $in .= '--' . $this->boundaryMixed . $this->CRLF;
410        $in .= "Content-Type: multipart/alternative; boundary=\"$this->boundaryAlternative\"" . $this->CRLF;
411        $in .= $this->CRLF;
412        $in .= "--" . $this->boundaryAlternative . $this->CRLF;
413        $in .= "Content-Type: text/plain; charset=\"" . $this->charset . "\"" . $this->CRLF;
414        $in .= "Content-Transfer-Encoding: base64" . $this->CRLF;
415        $in .= $this->CRLF;
416        $in .= chunk_split(base64_encode($this->body)) . $this->CRLF;
417        $in .= $this->CRLF;
418        $in .= "--" . $this->boundaryAlternative . $this->CRLF;
419        $in .= "Content-Type: text/html; charset=\"" . $this->charset ."\"" . $this->CRLF;
420        $in .= "Content-Transfer-Encoding: base64" . $this->CRLF;
421        $in .= $this->CRLF;
422        $in .= chunk_split(base64_encode($this->body)) . $this->CRLF;
423        $in .= $this->CRLF;
424        $in .= "--" . $this->boundaryAlternative . "--" . $this->CRLF;
425        foreach ($this->attachment as $name => $path){
426            $in .= $this->CRLF;
427            $in .= '--' . $this->boundaryMixed . $this->CRLF;
428            $in .= "Content-Type: application/octet-stream; name=\"". $name ."\"" . $this->CRLF;
429            $in .= "Content-Transfer-Encoding: base64" . $this->CRLF;
430            $in .= "Content-Disposition: attachment; filename=\"" . $name . "\"" . $this->CRLF;
431            $in .= $this->CRLF;
432            $in .= chunk_split(base64_encode(file_get_contents($path))) . $this->CRLF;
433        }
434        $in .= $this->CRLF;
435        $in .= $this->CRLF;
436        $in .= '--' . $this->boundaryMixed . '--' . $this->CRLF;
437        return $in;
438    }
439
440    public function toString()
441    {
442        $in = '';
443        $this->createHeader();
444        foreach ($this->header as $key => $value) {
445            $in .= $key . ': ' . $value . $this->CRLF;
446        }
447        if (empty($this->attachment)) {
448            $in .= $this->createBody();
449        } else {
450            $in .= $this->createBodyWithAttachment();
451        }
452        $in .= $this->CRLF . $this->CRLF . "." . $this->CRLF;
453        return $in;
454    }
455
456}
457