├── LICENSE
├── README.md
├── composer.json
├── composer.lock
├── index.php
└── src
└── phpImapReader
├── Email.php
├── EmailAttachment.php
└── Reader.php
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 benhall14
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PHP IMAP Reader
2 | A PHP class that makes working with IMAP as easy as possible.
3 |
4 | This class is written to be chain-able so to create a logically fluent and easily readable way to access an IMAP mailbox.
5 |
6 | It simplifies the PHP IMAP_* library into a set of easy to read methods that do the heavy lifting for you.
7 |
8 | It has been fully tested to work with PHP 5.3+, including **PHP 8.1.**
9 |
10 | # Installation via Composer
11 | You can now install this class via composer.
12 |
13 | $ composer require benhall14/php-imap-reader
14 |
15 | **Remember** to add the composer autoloader before using the class and use the correct namespace.
16 |
17 | require 'vendor/autoload.php';
18 |
19 | use benhall14\phpImapReader\Email as Email;
20 | use benhall14\phpImapReader\EmailAttachment as EmailAttachment;
21 | use benhall14\phpImapReader\Reader as Reader;
22 |
23 | # Usage
24 | Please make sure you have added the required classes.
25 |
26 | In its simplest form, use the following to connect:
27 |
28 | ```php
29 | define('IMAP_USERNAME', ''); # your imap user name
30 | define('IMAP_PASSWORD', ''); # your imap password
31 | define('IMAP_MAILBOX', ''); # your imap address EG. {mail.example.com:993/novalidate-cert/ssl}
32 | define('ATTACHMENT_PATH', __DIR__ . '/attachments'); # the path to save attachments to or false to skip attachments
33 |
34 | try{
35 |
36 | # set the mark as read flag (true by default). If you don't want emails to be marked as read/seen, set this to false.
37 | $mark_as_read = true;
38 |
39 | # You can ommit this to use UTF-8 by default.
40 | $encoding = 'UTF-8'
41 |
42 | # create a new Reader object
43 | $imap = new Reader(IMAP_MAILBOX, IMAP_USERNAME, IMAP_PASSWORD, ATTACHMENT_PATH, $mark_as_read, $encoding);
44 |
45 | # use one or more of the following chain-able methods to filter your email selection
46 | $imap
47 | ->folder($folder) # alias for mailbox($mailbox)
48 | ->mailbox($mailbox) # sets the mailbox to return emails from. Default = INBOX
49 | ->id($id) # retrieve a specific email by id
50 | ->recent() # get all RECENT emails
51 | ->flagged() # get all FLAGGED emails
52 | ->unflagged() # get all UNFLAGGED emails
53 | ->unanswered() # get all UNANSWERED emails
54 | ->deleted() # get all DELETED emails
55 | ->unread() # alias for UNSEEN()
56 | ->unseen() # get all UNSEEN emails
57 | ->from($email) # get all emails from $email
58 | ->searchSubject($string) # get all emails with $string in the subject line
59 | ->searchBody($string) # get all emails with $string in the body
60 | ->searchText($string) # get all emails with $string TEXT
61 | ->seen() # get all SEEN emails
62 | ->read() # alias for SEEN()
63 | ->newMessages() # get all NEW emails
64 | ->oldMessages() # get all OLD emails
65 | ->keyword($keyword) # get all emails with $keyword KEYWORD
66 | ->unkeyword($keyword) # get all emails without $keyword KEYWORD
67 | ->beforeDate($date) # get all emails received before $date. *Date should be in a format that can be parsed by strtotime.*
68 | ->sinceDate($date) # get all emails received since $date. *Date should be in a format that can be parsed by strtotime.*
69 | ->sentTo($to) # get all emails sent to $to
70 | ->searchBCC($string) # get all emails with $string in the BCC field
71 | ->searchCC($string) # get all emails with $string in the CC field
72 | ->onDate($date) # get all emails received on $date. *Date should be in a format that can be parsed by strtotime.*
73 | ->limit($limit) # limit the number of emails returned to $limit for pagination
74 | ->page($page) # used with limit to create pagination
75 | ->orderASC() # order the emails returned in ASCending order
76 | ->orderDESC() # order the emails returned in DESCendeing order
77 | ->reset() # resets the current reader to be able to reconnect to another folder/mailbox.
78 | ->all() # get all emails (default)
79 | ->get(); # finally make the connection and retrieve the emails.
80 |
81 | # You can then loop through $imap->emails() for each email.
82 | foreach($imap->emails() as $email){
83 |
84 | # The email has been clean and formated.
85 | # see below.
86 |
87 | }
88 |
89 | # Reset the reader and connect to another folder.
90 | $imap->reset()->folder('Sent')->get();
91 |
92 | # You can also create a folder/mailbox on the IMAP stream.
93 | $imap->createFolder('New Folder Name');
94 | #or
95 | $imap->createMailbox('New Folder Name');
96 |
97 | # You can also check if a mailbox/folder exists on the IMAP stream using:
98 | if ($imap->doesMailboxExists('INBOX')) {
99 | return "Yes, it exsits";
100 | } else {
101 | return "No, it doesn't exist.";
102 | }
103 |
104 | # ... your code here ...
105 |
106 | } catch (Exception $e){
107 |
108 | echo $e->getMessage();
109 |
110 | }
111 | ```
112 |
113 | While looping through the returned emails, each email object can be used as below:
114 | ```php
115 |
116 | $email->isTo('mail@example.com'); # Return true if the email is to $email, else returns false
117 |
118 | $email->replyTo(); # Returns an array of Reply To email addresses (and names)
119 |
120 | $email->cc(); # Returns an array of CC email addresses (and names)
121 |
122 | $email->to(); # Returns the recipient email address
123 |
124 | $email->id(); # Returns the id of the email
125 |
126 | $email->size(); # Returns the size of the email
127 |
128 | $email->date($format); # Returns the date in the $format specified. Default Y-m-d H:i:s
129 |
130 | $email->subject(); # Returns the email subject
131 |
132 | $email->fromName(); # Returns the sender's name, if set.
133 |
134 | $email->fromEmail(); # Returns the sender's email address
135 |
136 | $email->plain(); # Returns the plain text body of the email, if present
137 |
138 | $email->html(); # Returns the html body of the email, if present
139 |
140 | $email->hasAttachments(); # Returns true/false based on if the email has attachments
141 |
142 | $email->attachments(); # Returns an array of EmailAttachment objects
143 |
144 | $email->attachment($id); # Returns an attachment based on the given attachment $id
145 |
146 | $email->isRecent(); # Returns true/false based on the recent flag
147 |
148 | $email->isUnseen(); # Returns true/false based on the unseen flag
149 |
150 | $email->isFlagged(); # Returns true/false based on the flagged flag
151 |
152 | $email->isAnswered(); # Returns true/false based on the answered flag
153 |
154 | $email->isDeleted(); # Returns true/false based on the deleted flag
155 |
156 | $email->isDraft(); # Returns true/false based on the draft flag
157 |
158 | $email->eml(); # Returns the email in .eml format
159 |
160 | $email->saveEml($filename); # Saves the email in .eml format
161 |
162 | $email->count(); # Returns number of emails in folder
163 |
164 | ```
165 |
166 | The **$email->attachments();** method returns an array of attachments belonging to the email in a **benhall14\phpImapReader\EmailAttachment** object. The following methods are available for each attachment.
167 |
168 | ```php
169 |
170 | # check if the current $email has any attachments.
171 | if($email->hasAttachments()){
172 |
173 | # get the attachments for the current $email in the loop.
174 | $attachments = $email->attachments();
175 |
176 | # loop through the found attachments.
177 | foreach($attachments as $attachment){
178 |
179 | $attachment->id(); # Returns the attachments ID.
180 |
181 | $attachment->name(); # Returns the attachments name.
182 |
183 | $attachment->filePath(); # Returns the local file path for the attachment. This is based on the ATTACHMENT_PATH constant set in the imap config.
184 |
185 | $attachment->content(); # Returns the attachments content data.
186 |
187 | $attachment->type(); # Returns either 'attachment' or 'inline'.
188 |
189 | }
190 |
191 | }
192 | ```
193 |
194 | # Requirements
195 |
196 | **Works with PHP 5.3+ (including PHP 8.1)**
197 |
198 | **PHP IMAP Extension**
199 |
200 | # License
201 | Copyright (c) 2016-2021 Benjamin Hall, ben@conobe.co.uk
202 | https://conobe.co.uk
203 |
204 | Licensed under the MIT license
205 |
206 | # Donate?
207 |
208 | If you find this project helpful or useful in anyway, please consider getting me a cup of coffee - It's really appreciated :)
209 |
210 | [](https://paypal.me/benhall14)
211 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "benhall14/php-imap-reader",
3 | "description": "A PHP class that makes working with IMAP in PHP simple.",
4 | "homepage": "https://github.com/benhall14/php-imap-reader",
5 | "keywords": ["imap", "mail", "php", "pop3", "mailbox", "email"],
6 | "license": "MIT",
7 | "type": "library",
8 | "authors": [
9 | {
10 | "name": "Benjamin Hall",
11 | "email": "ben@conobe.co.uk",
12 | "homepage": "https://conobe.co.uk",
13 | "role": "Developer"
14 | }
15 | ],
16 | "require": {
17 | "php": ">=5.3",
18 | "ext-imap": "*"
19 | },
20 | "autoload": {
21 | "psr-4": {
22 | "benhall14\\": "src/"
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/composer.lock:
--------------------------------------------------------------------------------
1 | {
2 | "_readme": [
3 | "This file locks the dependencies of your project to a known state",
4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
5 | "This file is @generated automatically"
6 | ],
7 | "content-hash": "074f9787659c58fd1437a1af846f0e0d",
8 | "packages": [],
9 | "packages-dev": [],
10 | "aliases": [],
11 | "minimum-stability": "stable",
12 | "stability-flags": [],
13 | "prefer-stable": false,
14 | "prefer-lowest": false,
15 | "platform": {
16 | "php": ">=5.3"
17 | },
18 | "platform-dev": []
19 | }
20 |
--------------------------------------------------------------------------------
/index.php:
--------------------------------------------------------------------------------
1 | limit(10)->get();
18 |
19 | foreach ($imap->emails() as $email) {
20 | echo '
';
21 |
22 | echo '
' . $email->fromEmail() . '
';
23 |
24 | echo '
' . $email->subject() . '
';
25 |
26 | echo '
' . $email->date('Y-m-d H:i:s') . '
';
27 |
28 | if ($email->hasAttachments()) {
29 | foreach ($email->attachments() as $attachment) {
30 | echo '
' . $attachment->filePath() . '
';
31 | }
32 | }
33 |
34 | #print_r($email->plain());
35 | #print_r($email->html());
36 |
37 | echo '
';
38 | }
39 | } catch (Exception $e) {
40 | die($e->getMessage());
41 | }
42 |
--------------------------------------------------------------------------------
/src/phpImapReader/Email.php:
--------------------------------------------------------------------------------
1 |
14 | * @copyright 2022 Copyright (c) Benjamin Hall
15 | * @license MIT https://github.com/benhall14/php-imap-reader
16 | * @link https://conobe.co.uk/projects/php-imap-reader/
17 | */
18 | class Email
19 | {
20 | /**
21 | * The ID of this email.
22 | *
23 | * @var int
24 | */
25 | public $id;
26 |
27 | /**
28 | * The msgno of this email.
29 | *
30 | * @var int
31 | */
32 | public $msgno;
33 |
34 | /**
35 | * The date this email was received.
36 | *
37 | * @var DateTime
38 | */
39 | public $date;
40 |
41 | /**
42 | * The UNIX time stamp when this email was received.
43 | *
44 | * @var int
45 | */
46 | public $udate;
47 |
48 | /**
49 | * An array containing the custom headers of the email.
50 | *
51 | * @var array
52 | */
53 | public $custom_headers = array();
54 |
55 | /**
56 | * The subject line of this email.
57 | *
58 | * @var string
59 | */
60 | public $subject;
61 |
62 | /**
63 | * The recipient of this email.
64 | *
65 | * @var array
66 | */
67 | public $to = array();
68 |
69 | /**
70 | * The sender of this email.
71 | *
72 | * @var string
73 | */
74 | public $from;
75 |
76 | /**
77 | * An array of Reply To email addresses.
78 | *
79 | * @var array
80 | */
81 | public $reply_to = array();
82 |
83 | /**
84 | * An array of Carbon Copy recipients.
85 | *
86 | * @var array
87 | */
88 | public $cc = array();
89 |
90 | /**
91 | * The 'recent' flag.
92 | *
93 | * @var boolean
94 | */
95 | public $recent;
96 |
97 | /**
98 | * The 'unseen' flag.
99 | *
100 | * @var boolean
101 | */
102 | public $unseen;
103 |
104 | /**
105 | * The 'flagged' flag.
106 | *
107 | * @var boolean
108 | */
109 | public $flagged;
110 |
111 | /**
112 | * The 'answered' flag.
113 | *
114 | * @var boolean
115 | */
116 | public $answered;
117 |
118 | /**
119 | * The 'deleted' flag.
120 | *
121 | * @var boolean
122 | */
123 | public $deleted;
124 |
125 | /**
126 | * The 'draft' flag.
127 | *
128 | * @var boolean
129 | */
130 | public $draft;
131 |
132 | /**
133 | * The integer size of this email.
134 | *
135 | * @var int
136 | */
137 | public $size;
138 |
139 | /**
140 | * The plain text body of this email.
141 | *
142 | * @var string
143 | */
144 | public $text_plain;
145 |
146 | /**
147 | * The HTML body of this email.
148 | *
149 | * @var string
150 | */
151 | public $text_html;
152 |
153 | /**
154 | * An array of attachments, including inline.
155 | *
156 | * @var array
157 | */
158 | public $attachments = array();
159 |
160 | /**
161 | * Raw Body
162 | *
163 | * @var string
164 | */
165 | public $raw_body;
166 |
167 | /**
168 | * Checks if the email recipient matches the given email address.
169 | *
170 | * @param string $email The email address to match against the recipient.
171 | *
172 | * @return boolean
173 | */
174 | public function isTo($email)
175 | {
176 | foreach ($this->to as $to) {
177 | if ($email == $to->email) {
178 | return true;
179 | }
180 | }
181 |
182 | return false;
183 | }
184 |
185 | /**
186 | * Get the 'Reply To' email addresses for this email.
187 | *
188 | * @return array
189 | */
190 | public function replyTo()
191 | {
192 | return $this->reply_to;
193 | }
194 |
195 | /**
196 | * Get the 'Carbon Copied' email addresses for this email.
197 | *
198 | * @return array An array of email addresses in the cc field.
199 | */
200 | public function cc()
201 | {
202 | return $this->cc;
203 | }
204 |
205 | /**
206 | * Get the recipient of this email.
207 | *
208 | * @return string
209 | */
210 | public function to()
211 | {
212 | return $this->to;
213 | }
214 |
215 | /**
216 | * Get the ID of this email.
217 | *
218 | * @return integer The ID of the email.
219 | */
220 | public function id()
221 | {
222 | return $this->id;
223 | }
224 |
225 | /**
226 | * Get the msgno of this email.
227 | *
228 | * @return integer The msgno of the email.
229 | */
230 | public function msgno()
231 | {
232 | return $this->msgno;
233 | }
234 |
235 | /**
236 | * Get the custom headers of this email.
237 | *
238 | * @return array The custom headers of the email.
239 | */
240 | public function customHeaders()
241 | {
242 | return $this->custom_headers;
243 | }
244 |
245 | /**
246 | * Get the size in bytes of this email.
247 | *
248 | * @return integer
249 | */
250 | public function size()
251 | {
252 | return (int) $this->size;
253 | }
254 |
255 | /**
256 | * Get the date that this email was received.
257 | *
258 | * @param string $format The format in which to return the date.
259 | *
260 | * @return string
261 | */
262 | public function date($format = 'Y-m-d H:i:s')
263 | {
264 | return $this->date->format($format);
265 | }
266 |
267 | /**
268 | * Get the subject line of this email.
269 | *
270 | * @return string
271 | */
272 | public function subject()
273 | {
274 | return $this->subject;
275 | }
276 |
277 | /**
278 | * Get the sender name of this email.
279 | *
280 | * @return string
281 | */
282 | public function fromName()
283 | {
284 | return $this->from && $this->from->name ? $this->from->name : null;
285 | }
286 |
287 | /**
288 | * Get the sender email address of this email.
289 | *
290 | * @return string
291 | */
292 | public function fromEmail()
293 | {
294 | return $this->from && $this->from->email ? $this->from->email : null;
295 | }
296 |
297 | /**
298 | * Get the plain text body of this email.
299 | *
300 | * @return string
301 | */
302 | public function plain()
303 | {
304 | return $this->text_plain;
305 | }
306 |
307 | /**
308 | * Get the HTML body of this email.
309 | *
310 | * @return string
311 | */
312 | public function html()
313 | {
314 | return $this->text_html ? $this->injectInline($this->text_html) : false;
315 | }
316 |
317 | /**
318 | * Return a boolean based on whether this email has attachments.
319 | *
320 | * @return boolean
321 | */
322 | public function hasAttachments()
323 | {
324 | return (count($this->attachments)) ? true : false;
325 | }
326 |
327 | /**
328 | * Return an array of the attachments for this email.
329 | *
330 | * @return array
331 | */
332 | public function attachments()
333 | {
334 | return $this->attachments;
335 | }
336 |
337 | /**
338 | * Return a specific attachment based on the attachment id.
339 | *
340 | * @param integer $attachment_id The attachment to return.
341 | *
342 | * @return EmailAttachment
343 | */
344 | public function attachment($attachment_id)
345 | {
346 | return isset($this->attachments[$attachment_id]) ? $this->attachments[$attachment_id] : false;
347 | }
348 |
349 | /**
350 | * Return the status of the recent flag.
351 | *
352 | * @return boolean
353 | */
354 | public function isRecent()
355 | {
356 | return $this->recent;
357 | }
358 |
359 | /**
360 | * Return the status of the unseen flag.
361 | *
362 | * @return boolean
363 | */
364 | public function isUnseen()
365 | {
366 | return $this->unseen;
367 | }
368 |
369 | /**
370 | * Return the status of the flagged flag.
371 | *
372 | * @return boolean
373 | */
374 | public function isFlagged()
375 | {
376 | return $this->flagged;
377 | }
378 |
379 | /**
380 | * Return the status of the answered flag.
381 | *
382 | * @return boolean
383 | */
384 | public function isAnswered()
385 | {
386 | return $this->answered;
387 | }
388 |
389 | /**
390 | * Return the status of the deleted flag.
391 | *
392 | * @return boolean
393 | */
394 | public function isDeleted()
395 | {
396 | return $this->deleted;
397 | }
398 |
399 | /**
400 | * Return the status of the draft flag.
401 | *
402 | * @return boolean
403 | */
404 | public function isDraft()
405 | {
406 | return $this->draft;
407 | }
408 |
409 | /**
410 | * Set the subject line for this email.
411 | *
412 | * @param string $subject The subject line string.
413 | *
414 | * @return Email
415 | */
416 | public function setSubject($subject)
417 | {
418 | $this->subject = $subject;
419 |
420 | return $this;
421 | }
422 |
423 | /**
424 | * Set the unique id for this email.
425 | *
426 | * @param integer $id The id.
427 | *
428 | * @return Email
429 | */
430 | public function setId($id)
431 | {
432 | $this->id = $id;
433 |
434 | return $this;
435 | }
436 |
437 | /**
438 | * Set the msgno for this email.
439 | *
440 | * @param integer $msgno The msgno.
441 | *
442 | * @return Email
443 | */
444 | public function setMsgno($msgno)
445 | {
446 | $this->msgno = $msgno;
447 |
448 | return $this;
449 | }
450 |
451 | /**
452 | * Sets the raw body.
453 | *
454 | * @param string $body
455 | *
456 | * @return Email
457 | */
458 | public function setRawBody($body)
459 | {
460 | $this->raw_body = $body;
461 |
462 | return $this;
463 | }
464 |
465 | /**
466 | * Set the date for this email.
467 | *
468 | * @param string $date The Date string.
469 | *
470 | * @return Email
471 | */
472 | public function setDate($date)
473 | {
474 | $this->date = new DateTime($date);
475 |
476 | return $this;
477 | }
478 |
479 | /**
480 | * Set the UNIX time stamp for this email.
481 | *
482 | * @param integer $date A UNIX time stamp.
483 | *
484 | * @return Email
485 | */
486 | public function setUdate($date)
487 | {
488 | $this->udate = $date;
489 |
490 | return $this;
491 | }
492 |
493 | /**
494 | * Set the size of this email.
495 | *
496 | * @param integer $size Size in bytes.
497 | *
498 | * @return Email
499 | */
500 | public function setSize($size)
501 | {
502 | $this->size = (int) $size;
503 |
504 | return $this;
505 | }
506 |
507 | /**
508 | * Sets the unseen flag based on the given boolean state.
509 | *
510 | * @param boolean $boolean The flag status.
511 | *
512 | * @return Email
513 | */
514 | public function setUnseen($boolean)
515 | {
516 | $this->unseen = (bool) $boolean;
517 |
518 | return $this;
519 | }
520 |
521 | /**
522 | * Sets the answered flag based on the given boolean state.
523 | *
524 | * @param boolean $boolean The flag status.
525 | *
526 | * @return Email
527 | */
528 | public function setAnswered($boolean)
529 | {
530 | $this->answered = (bool) $boolean;
531 |
532 | return $this;
533 | }
534 |
535 | /**
536 | * Sets the draft flag based on the given boolean state.
537 | *
538 | * @param boolean $boolean The flag status.
539 | *
540 | * @return Email
541 | */
542 | public function setDraft($boolean)
543 | {
544 | $this->draft = (bool) $boolean;
545 |
546 | return $this;
547 | }
548 |
549 | /**
550 | * Sets the recent flag based on the given boolean state.
551 | *
552 | * @param boolean $boolean The flag status.
553 | *
554 | * @return Email
555 | */
556 | public function setRecent($boolean)
557 | {
558 | $this->recent = (bool) $boolean;
559 |
560 | return $this;
561 | }
562 |
563 | /**
564 | * Sets the flagged flag based on the given boolean state.
565 | *
566 | * @param boolean $boolean The flag status.
567 | *
568 | * @return Email
569 | */
570 | public function setFlagged($boolean)
571 | {
572 | $this->flagged = (bool) $boolean;
573 |
574 | return $this;
575 | }
576 |
577 | /**
578 | * Sets the deleted flag based on the given boolean state.
579 | *
580 | * @param boolean $boolean The flag status.
581 | *
582 | * @return Email
583 | */
584 | public function setDeleted($boolean)
585 | {
586 | $this->deleted = (bool) $boolean;
587 |
588 | return $this;
589 | }
590 |
591 | /**
592 | * Adds a recipient to the 'To' array.
593 | *
594 | * @param string $mailbox The mailbox.
595 | * @param string $host The host name.
596 | * @param string $name (optional) The recipient name.
597 | *
598 | * @return Email
599 | */
600 | public function addTo($mailbox, $host, $name = false)
601 | {
602 | if (!$mailbox || !$host) {
603 | return false;
604 | }
605 |
606 | $to = new stdClass();
607 |
608 | $to->name = ($name) ? $name : false;
609 |
610 | $to->mailbox = $mailbox;
611 |
612 | $to->host = $host;
613 |
614 | $to->email = $to->mailbox . '@' . $to->host;
615 |
616 | $this->to[] = $to;
617 |
618 | return $this;
619 | }
620 |
621 | /**
622 | * Adds a 'Reply To' to 'Reply To' array.
623 | *
624 | * @param string $mailbox The mailbox.
625 | * @param string $host The host name.
626 | * @param string $name (optional) The reply to name.
627 | *
628 | * @return Email
629 | */
630 | public function addReplyTo($mailbox, $host, $name = false)
631 | {
632 | if (!$mailbox || !$host) {
633 | return false;
634 | }
635 |
636 | $reply_to = new stdClass();
637 |
638 | $reply_to->name = ($name) ? $name : false;
639 |
640 | $reply_to->mailbox = $mailbox;
641 |
642 | $reply_to->host = $host;
643 |
644 | $reply_to->email = $reply_to->mailbox . '@' . $reply_to->host;
645 |
646 | $this->reply_to[] = $reply_to;
647 |
648 | return $this;
649 | }
650 |
651 | /**
652 | * Adds a custom header to this email.
653 | *
654 | * @param string $custom_header The custom header to append to the array.
655 | *
656 | * @return Email
657 | */
658 | public function addCustomHeader($custom_header)
659 | {
660 | if (!$custom_header) {
661 | return false;
662 | }
663 |
664 | $header_info = explode(":", $custom_header);
665 |
666 | if (is_array($header_info) && isset($header_info[0]) && isset($header_info[1])) {
667 | $this->custom_headers[$header_info[0]] = (string) trim($header_info[1]);
668 | }
669 |
670 | return $this;
671 | }
672 |
673 | /**
674 | * Returns a specific header (if it exists), or returns null.
675 | *
676 | * @param string $header_name
677 | *
678 | * @return string
679 | */
680 | public function getCustomHeader($header_name)
681 | {
682 | return isset($this->custom_headers) && isset($this->custom_headers[$header_name]) ? $this->custom_headers[$header_name] : null;
683 | }
684 |
685 | /**
686 | * An alias for getCustomHeader
687 | *
688 | * @param string $header_name
689 | *
690 | * @return string
691 | */
692 | public function getHeader($header_name)
693 | {
694 | return $this->getCustomHeader($header_name);
695 | }
696 |
697 | /**
698 | * Returns, or saves, the .eml version of the email.
699 | *
700 | * @param mixed $filename
701 | *
702 | * @return string
703 | */
704 | public function eml($filename = null)
705 | {
706 | if ($filename && !file_exists($filename)) {
707 | file_put_contents($filename, $this->raw_body);
708 | }
709 |
710 | return $this->raw_body;
711 | }
712 |
713 | /**
714 | * Save the Email as an .eml file.
715 | *
716 | * @param string $filename
717 | *
718 | * @return string
719 | */
720 | public function saveEml($filename)
721 | {
722 | return $this->eml($filename);
723 | }
724 |
725 | /**
726 | * Adds a carbon copy entry to this email.
727 | *
728 | * @param string $mailbox The mailbox.
729 | * @param string $host The host name.
730 | * @param string $name (optional) The name of the CC.
731 | *
732 | * @return Email
733 | */
734 | public function addCC($mailbox, $host, $name = false)
735 | {
736 | if (!$mailbox || !$host) {
737 | return false;
738 | }
739 |
740 | $cc = new stdClass();
741 |
742 | $cc->name = $name ?: false;
743 |
744 | $cc->mailbox = $mailbox;
745 |
746 | $cc->host = $host;
747 |
748 | $cc->email = $cc->mailbox . '@' . $cc->host;
749 |
750 | $this->cc[] = $cc;
751 |
752 | return $this;
753 | }
754 |
755 | /**
756 | * Set the 'from' email address for this email.
757 | *
758 | * @param string $mailbox The mailbox.
759 | * @param string $host The host name.
760 | * @param string $name (optional) The senders name.
761 | *
762 | * @return Email
763 | */
764 | public function setFrom($mailbox, $host, $name = false)
765 | {
766 | $this->from = new stdClass();
767 |
768 | $this->from->name = $name ?: false;
769 |
770 | $this->from->mailbox = $mailbox;
771 |
772 | $this->from->host = $host;
773 |
774 | $this->from->email = $this->from->mailbox . '@' . $this->from->host;
775 |
776 | return $this;
777 | }
778 |
779 | /**
780 | * Updates the HTML text body by concatenating the given
781 | * string to the current HTML body.
782 | *
783 | * @param string $html The HTML string to be added to the HTML text body.
784 | *
785 | * @return Email
786 | */
787 | public function setHTML($html)
788 | {
789 | $this->text_html .= trim($html);
790 |
791 | return $this;
792 | }
793 |
794 | /**
795 | * Updates the plain text body by concatenating the given
796 | * string to the current plain text body.
797 | *
798 | * @param string $plain The text string to be added to the plain text body.
799 | *
800 | * @return Email
801 | */
802 | public function setPlain($plain)
803 | {
804 | $this->text_plain .= trim($plain);
805 |
806 | return $this;
807 | }
808 |
809 | /**
810 | * Adds an attachment to this email.
811 | *
812 | * @param EmailAttachment $attachment An attachment object.
813 | *
814 | * @return Email
815 | */
816 | public function addAttachment(EmailAttachment $attachment)
817 | {
818 | $this->attachments[$attachment->id()] = $attachment;
819 |
820 | return $this;
821 | }
822 |
823 | /**
824 | * Inject in-line attachments by replacing the attachment ids
825 | * with the attachment file path.
826 | *
827 | * @param string $body The email body to have attachments injected.
828 | *
829 | * @return string
830 | */
831 | public function injectInline($body)
832 | {
833 | if ($this->attachments) {
834 | foreach ($this->attachments as $attachment) {
835 | if ($attachment->isInline()) {
836 | if ($attachment->id() && $attachment->filePath()) {
837 | $body = str_replace('cid:' . $attachment->id(), $attachment->filePath(), $body);
838 | }
839 | }
840 | }
841 | }
842 |
843 | return $body;
844 | }
845 | }
846 |
--------------------------------------------------------------------------------
/src/phpImapReader/EmailAttachment.php:
--------------------------------------------------------------------------------
1 |
11 | * @copyright 2022 Copyright (c) Benjamin Hall
12 | * @license MIT https://github.com/benhall14/php-imap-reader
13 | * @link https://conobe.co.uk/projects/php-imap-reader/
14 | */
15 | class EmailAttachment
16 | {
17 | /**
18 | * The attachment id
19 | *
20 | * @var int
21 | */
22 | public $id;
23 |
24 | /**
25 | * The attachment name.
26 | *
27 | * @var string
28 | */
29 | public $name;
30 |
31 | /**
32 | * The attachment file path.
33 | *
34 | * @var string
35 | */
36 | public $file_path;
37 |
38 | /**
39 | * The attachment type.
40 | *
41 | * @var string
42 | */
43 | public $type;
44 |
45 | /**
46 | * The attachment mime type.
47 | *
48 | * @var string
49 | */
50 | public $mime;
51 |
52 | /**
53 | * The attachment data.
54 | *
55 | * @var string
56 | */
57 | public $attachment_data;
58 |
59 | /**
60 | * Sets the attachments id.
61 | *
62 | * @param int $id The attachment id.
63 | *
64 | * @return EmailAttachment
65 | */
66 | public function setID($id)
67 | {
68 | $this->id = $id;
69 |
70 | return $this;
71 | }
72 |
73 | /**
74 | * Sets the attachments name.
75 | *
76 | * @param string $name The attachment name.
77 | *
78 | * @return EmailAttachment
79 | */
80 | public function setName($name)
81 | {
82 | $this->name = $name;
83 |
84 | return $this;
85 | }
86 |
87 | /**
88 | * Sets the attachment type.
89 | *
90 | * @param string $type The attachment type.
91 | *
92 | * @return EmailAttachment
93 | */
94 | public function setType($type)
95 | {
96 | $this->type = $type;
97 |
98 | return $this;
99 | }
100 |
101 | /**
102 | * Sets the attachment mime type.
103 | *
104 | * @param string $mime_type The attachment mime type.
105 | *
106 | * @return EmailAttachment
107 | */
108 | public function setMime($mime_type)
109 | {
110 | $this->mime = $mime_type;
111 |
112 | return $this;
113 | }
114 |
115 | /**
116 | * Sets the attachments file path.
117 | *
118 | * @param string $file_path The attachment file path.
119 | *
120 | * @return EmailAttachment
121 | */
122 | public function setFilePath($file_path)
123 | {
124 | $this->file_path = $file_path;
125 |
126 | return $this;
127 | }
128 |
129 | /**
130 | * Sets the attachments data
131 | *
132 | * @param string $data The attachment data.
133 | *
134 | * @return EmailAttachment
135 | */
136 | public function setAttachmentData($data)
137 | {
138 | $this->attachment_data = $data;
139 |
140 | return $this;
141 | }
142 |
143 | /**
144 | * Get the attachments id.
145 | *
146 | * @return integer
147 | */
148 | public function id()
149 | {
150 | return $this->id;
151 | }
152 |
153 | /**
154 | * Get the attachments name.
155 | *
156 | * @return string
157 | */
158 | public function name()
159 | {
160 | return $this->name;
161 | }
162 |
163 | /**
164 | * Get the attachments file path.
165 | *
166 | * @return string
167 | */
168 | public function filePath()
169 | {
170 | return $this->file_path;
171 | }
172 |
173 | /**
174 | * Get the attachments content.
175 | *
176 | * @return string
177 | */
178 | public function content()
179 | {
180 | return $this->attachment_data;
181 | }
182 |
183 | /**
184 | * Get the attachments type.
185 | *
186 | * @return string
187 | */
188 | public function type()
189 | {
190 | return $this->type;
191 | }
192 |
193 | /**
194 | * Gets the inline status of the attachment.
195 | *
196 | * @return boolean
197 | */
198 | public function isInline()
199 | {
200 | return $this->type() == 'inline' ? true : false;
201 | }
202 | }
203 |
--------------------------------------------------------------------------------
/src/phpImapReader/Reader.php:
--------------------------------------------------------------------------------
1 |
15 | * @copyright 2022 Copyright (c) Benjamin Hall
16 | * @license MIT https://github.com/benhall14/php-imap-reader
17 | * @link https://conobe.co.uk/projects/php-imap-reader/
18 | */
19 | class Reader
20 | {
21 | /**
22 | * The IMAP host name.
23 | *
24 | * @var string
25 | */
26 | public $hostname;
27 |
28 | /**
29 | * The IMAP user name.
30 | *
31 | * @var string
32 | */
33 | public $user_name;
34 |
35 | /**
36 | * The IMAP password.
37 | *
38 | * @var string
39 | */
40 | public $password;
41 |
42 | /**
43 | * The IMAP Encoding
44 | *
45 | * @var string
46 | */
47 | public $encoding;
48 |
49 | /**
50 | * Save attachment status - should we save attachments.
51 | *
52 | * @var boolean
53 | */
54 | public $save_attachments;
55 |
56 | /**
57 | * Retry status
58 | *
59 | * @var boolean
60 | */
61 | public $retry;
62 |
63 | /**
64 | * The IMAP handler.
65 | *
66 | * @var resource
67 | */
68 | public $imap;
69 |
70 | /**
71 | * The index of email ids.
72 | *
73 | * @var array
74 | */
75 | public $email_index;
76 |
77 | /**
78 | * The array of previously fetched emails
79 | *
80 | * @var array
81 | */
82 | public $emails = array();
83 |
84 | /**
85 | * Modes - such as NEW or UNSEEN.
86 | *
87 | * @var array
88 | */
89 | public $modes = array();
90 |
91 | /**
92 | * The id of an specific id.
93 | *
94 | * @var int
95 | */
96 | public $id = 0;
97 |
98 | /**
99 | * Limit the number of emails fetch. Can be used with page for pagination.
100 | *
101 | * @var int
102 | */
103 | public $limit = 0;
104 |
105 | /**
106 | * Page number. Can be used with limit for pagination.
107 | *
108 | * @var int
109 | */
110 | public $page = 0;
111 |
112 | /**
113 | * The email offset.
114 | *
115 | * @var int
116 | */
117 | public $offset = 0;
118 |
119 | /**
120 | * The sorting order direction.
121 | *
122 | * @var string
123 | */
124 | public $order = 'DESC';
125 |
126 | /**
127 | * The mailbox name.
128 | *
129 | * @var string
130 | */
131 | public $mailbox = 'INBOX';
132 |
133 | /**
134 | * Defines whether the email should be auto-marked as read.
135 | *
136 | * @var boolean
137 | */
138 | public $mark_as_read = false;
139 |
140 | /**
141 | * Defines the attachment directory on disk.
142 | *
143 | * @var string
144 | */
145 | public $attachment_dir = null;
146 |
147 | /**
148 | * Sets the IMAP Reader
149 | *
150 | * @param string $hostname The IMAP host name.
151 | * @param string $user_name The IMAP user name.
152 | * @param string $password The IMAP password.
153 | * @param mixed $attachment_dir The directory path to store attachments or false to turn off saving attachments.
154 | * @param bool $mark_as_read Whether we should mark as read.
155 | *
156 | * @return boolean
157 | */
158 | public function __construct($hostname, $user_name, $password, $attachment_dir = false, $mark_as_read = true, $encoding = 'UTF-8')
159 | {
160 | $this->hostname = $hostname;
161 |
162 | $this->user_name = $user_name;
163 |
164 | $this->password = $password;
165 |
166 | $this->encoding = $encoding;
167 |
168 | $this->retry = 0;
169 |
170 | $this->mark_as_read = $mark_as_read;
171 |
172 | $this->save_attachments = false;
173 |
174 | if ($attachment_dir) {
175 | if (!is_dir($attachment_dir)) {
176 | throw new Exception(
177 | 'ERROR: Directory "' . $attachment_dir . '" could not be found.'
178 | );
179 | }
180 |
181 | if (!is_writable($attachment_dir)) {
182 | throw new Exception(
183 | 'ERROR: Directory "' . $attachment_dir . '" is not writable.'
184 | );
185 | }
186 |
187 | $this->save_attachments = true;
188 | $this->attachment_dir = $attachment_dir;
189 | }
190 |
191 | return true;
192 | }
193 |
194 | /**
195 | * Returns true/false based on if $imap is an imap resource.
196 | *
197 | * @param mixed $imap
198 | *
199 | * @return boolean
200 | */
201 | public function isImapResource($imap)
202 | {
203 | return is_resource($imap) && 'imap' == \get_resource_type($imap);
204 | }
205 |
206 | /**
207 | * Fetch the active IMAP stream. If no stream is active, try a connection.
208 | *
209 | * @param boolean $reconnect Whether to reconnect connection.
210 | *
211 | * @return resource
212 | */
213 | public function stream($reconnect = false)
214 | {
215 | if ($this->imap && (!$this->isImapResource($this->imap) || !imap_ping($this->imap))) {
216 | $this->close();
217 |
218 | $this->imap = false;
219 | }
220 |
221 | if (!$this->imap || $reconnect) {
222 | $this->imap = $this->connect();
223 | }
224 |
225 | return $this->imap;
226 | }
227 |
228 | /**
229 | * Connect to an IMAP stream.
230 | *
231 | * @return resource
232 | */
233 | public function connect()
234 | {
235 | $stream = imap_open(
236 | $this->hostname . $this->mailbox,
237 | $this->user_name,
238 | $this->password,
239 | false,
240 | $this->retry
241 | );
242 |
243 | if (!$stream) {
244 | $last_error = imap_last_error();
245 |
246 | imap_errors();
247 |
248 | throw new Exception('ERROR: Could Not Connect (' . $last_error . ')');
249 | }
250 |
251 | return $stream;
252 | }
253 |
254 | /**
255 | * Close the current IMAP stream.
256 | *
257 | * @return Reader
258 | */
259 | public function close()
260 | {
261 | if ($this->isImapResource($this->imap)) {
262 | imap_close($this->imap, CL_EXPUNGE);
263 | }
264 |
265 | return $this;
266 | }
267 |
268 | /**
269 | * Resets the reader to be able to connect to another folder.
270 | *
271 | * @return Reader
272 | */
273 | public function reset()
274 | {
275 | $this->close();
276 |
277 | $this->emails = [];
278 |
279 | return $this;
280 | }
281 |
282 | /**
283 | * Close connection on destruct.
284 | *
285 | * @return Reader
286 | */
287 | public function __destruct()
288 | {
289 | return $this->close();
290 | }
291 |
292 | /**
293 | * The number of emails found.
294 | *
295 | * @return int
296 | */
297 | public function count()
298 | {
299 | return imap_num_msg($this->stream());
300 | }
301 |
302 | /**
303 | * Get the last error.
304 | *
305 | * @return string The error message.
306 | */
307 | public function getError()
308 | {
309 | return imap_last_error();
310 | }
311 |
312 | /**
313 | * Alias for doesMailboxExist - Returns true/false based on if the specified folder/mailbox exists on the IMAP stream.
314 | *
315 | * @param string $folder_name
316 | *
317 | * @return boolean.
318 | */
319 | public function doesFolderExist($folder_name = null)
320 | {
321 | return $this->doesMailboxExist($folder_name);
322 | }
323 |
324 | /**
325 | * Returns true/false based on if the specified folder/mailbox exists on the IMAP stream.
326 | *
327 | * @param string $mailbox
328 | *
329 | * @return boolean
330 | */
331 | public function doesMailboxExist($mailbox)
332 | {
333 | if (!$mailbox) {
334 | return false;
335 | }
336 |
337 | $mailboxes = imap_list($this->stream(), $this->hostname, "*");
338 |
339 | if (!in_array($this->hostname . $mailbox, $mailboxes)) {
340 | return false;
341 | }
342 |
343 | return true;
344 | }
345 |
346 | /**
347 | * Create a new folder/mailbox on the IMAP stream.
348 | *
349 | * @param string $folder_name
350 | *
351 | * @return boolean
352 | */
353 | public function makeFolder($folder_name = null)
354 | {
355 | if (!$folder_name) {
356 | return false;
357 | }
358 |
359 | if ($this->doesFolderExist($folder_name)) {
360 | return false;
361 | }
362 |
363 | return imap_createmailbox($this->stream(), imap_utf7_encode($this->hostname . $folder_name));
364 | }
365 |
366 | /**
367 | * Alias for makeFolder. Creates a new folder/mailbox on the IMAP stream.
368 | *
369 | * @param string $folder_name
370 | *
371 | * @return boolean
372 | */
373 | public function createFolder($folder_name)
374 | {
375 | return $this->makeFolder($folder_name);
376 | }
377 |
378 | /**
379 | * Alias for makeFolder. Create a new folder/mailbox on the IMAP stream.
380 | *
381 | * @param string $mailbox
382 | *
383 | * @return boolean
384 | */
385 | public function createMailbox($mailbox = null)
386 | {
387 | return $this->makeFolder($mailbox);
388 | }
389 |
390 | /**
391 | * Alias for makeFolder. Create a new folder/mailbox on the IMAP stream.
392 | *
393 | * @param string $mailbox
394 | *
395 | * @return boolean
396 | */
397 | public function makeMailbox($mailbox = null)
398 | {
399 | return $this->makeFolder($mailbox);
400 | }
401 |
402 | /**
403 | * Delete an email by given email id.
404 | *
405 | * @param int $email_id The id of the email to delete.
406 | *
407 | * @return boolean
408 | */
409 | public function deleteEmail($email_id)
410 | {
411 | return imap_delete($this->stream(), $email_id, FT_UID);
412 | }
413 |
414 | /**
415 | * Expunge all emails that are marked for deletion on the connected inbox.
416 | *
417 | * @return boolean
418 | */
419 | public function expunge()
420 | {
421 | return imap_expunge($this->stream());
422 | }
423 |
424 | /**
425 | * Mark an email as read by given email id.
426 | *
427 | * @param int $email_id The id of the email to mark as read.
428 | *
429 | * @return boolean
430 | */
431 | public function markAsRead($email_id)
432 | {
433 | return imap_setflag_full($this->stream(), $email_id, '\\Seen', ST_UID);
434 | }
435 |
436 | /**
437 | * Move mail to specific folder
438 | * @param int $email_id The id of the email to move.
439 | * @param string $folder Destination folder
440 | * @return boolean The result of the action.
441 | */
442 | public function moveEmailToFolder($email_id, $folder)
443 | {
444 | if ($this->mailbox == $folder) {
445 | return false;
446 | }
447 |
448 | return imap_mail_move($this->stream(), (string) $email_id, $folder, CP_UID);
449 | }
450 |
451 | /**
452 | * Get the list of emails from the last get call.
453 | *
454 | * @return array An array of returned emails.
455 | */
456 | public function emails()
457 | {
458 | return $this->emails;
459 | }
460 |
461 | /**
462 | * Get the first email from the list of returned emails. This is a shortcut for $this->emails[0];
463 | *
464 | * @return Email The email.
465 | */
466 | public function email()
467 | {
468 | return $this->emails && isset($this->emails[0])
469 | ? $this->emails[0] : null;
470 | }
471 |
472 | /**
473 | * Get the email based on the given id.
474 | *
475 | * @param int $id The Email Id.
476 | *
477 | * @return Reader
478 | */
479 | public function id($id)
480 | {
481 | $this->id = (int) $id;
482 |
483 | return $this;
484 | }
485 |
486 | /**
487 | * Add 'all' to the mode selection.
488 | * This allows for matching 'all' emails.
489 | *
490 | * @return Reader
491 | */
492 | public function all()
493 | {
494 | $this->modes[] = 'ALL';
495 |
496 | return $this;
497 | }
498 |
499 | /**
500 | * Add 'flagged' to the mode selection.
501 | * This allows for matching 'flagged' emails.
502 | *
503 | * @return Reader
504 | */
505 | public function flagged()
506 | {
507 | $this->modes[] = 'FLAGGED';
508 |
509 | return $this;
510 | }
511 |
512 | /**
513 | * Add 'unanswered' to the mode selection.
514 | * This allows for matching 'unanswered' emails.
515 | *
516 | * @return Reader
517 | */
518 | public function unanswered()
519 | {
520 | $this->modes[] = 'UNANSWERED';
521 |
522 | return $this;
523 | }
524 |
525 | /**
526 | * Add 'deleted' to the mode selection.
527 | * This allows for matching 'deleted' emails.
528 | *
529 | * @return Reader
530 | */
531 | public function deleted()
532 | {
533 | $this->modes[] = 'DELETED';
534 |
535 | return $this;
536 | }
537 |
538 | /**
539 | * Add 'unseen' to the mode selection.
540 | * This allows for matching 'unseen' emails.
541 | *
542 | * @return Reader
543 | */
544 | public function unseen()
545 | {
546 | $this->modes[] = 'UNSEEN';
547 |
548 | return $this;
549 | }
550 |
551 | /**
552 | * An alias of unseen. See unseen().
553 | *
554 | * @return void
555 | */
556 | public function unread()
557 | {
558 | return $this->unseen();
559 | }
560 |
561 | /**
562 | * Add 'from' to the mode selection.
563 | * This allows for matching emails 'from' the given email address.
564 | *
565 | * @param string $from The sender email address.
566 | *
567 | * @return Reader
568 | */
569 | public function from($from)
570 | {
571 | $this->modes[] = 'FROM "' . $from . '"';
572 |
573 | return $this;
574 | }
575 |
576 | /**
577 | * Add the body search to the mode selection.
578 | * This allows for searching for a string within a body
579 | *
580 | * @param string $string The search keywords.
581 | *
582 | * @return Reader
583 | */
584 | public function searchBody($string)
585 | {
586 | if ($string) {
587 | $this->modes[] = 'BODY "' . $string . '"';
588 | }
589 |
590 | return $this;
591 | }
592 |
593 | /**
594 | * Add the subject search to the mode selection.
595 | * This allows for searching for a string within a subject line.
596 | *
597 | * @param string $string The string to search for.
598 | *
599 | * @return Reader
600 | */
601 | public function searchSubject($string)
602 | {
603 | if ($string) {
604 | $this->modes[] = 'SUBJECT "' . $string . '"';
605 | }
606 |
607 | return $this;
608 | }
609 |
610 | /**
611 | * Add the recent flag to the mode selection.
612 | * This allows for matching recent emails.
613 | *
614 | * @return Reader
615 | */
616 | public function recent()
617 | {
618 | $this->modes[] = 'RECENT';
619 |
620 | return $this;
621 | }
622 |
623 | /**
624 | * Add the unflagged flag to the mode selection.
625 | * This allows for matching unflagged emails.
626 | *
627 | * @return Reader
628 | */
629 | public function unflagged()
630 | {
631 | $this->modes[] = 'UNFLAGGED';
632 |
633 | return $this;
634 | }
635 |
636 | /**
637 | * Add the seen flag to the mode selection.
638 | * This allows for matching seen emails.
639 | *
640 | * @return Reader
641 | */
642 | public function seen()
643 | {
644 | $this->modes[] = 'SEEN';
645 |
646 | return $this;
647 | }
648 |
649 | /**
650 | * Alias of seen(). See Seen().
651 | *
652 | * @return void
653 | */
654 | public function read()
655 | {
656 | $this->seen();
657 | }
658 |
659 | /**
660 | * Add the new flag to the mode selection. This allows for matching new emails.
661 | *
662 | * @return Reader
663 | */
664 | public function newMessages()
665 | {
666 | $this->modes[] = 'NEW';
667 |
668 | return $this;
669 | }
670 |
671 | /**
672 | * Add the old flag to the mode selection.
673 | * This allows for matching old emails.
674 | *
675 | * @return Reader
676 | */
677 | public function oldMessages()
678 | {
679 | $this->modes[] = 'OLD';
680 |
681 | return $this;
682 | }
683 |
684 | /**
685 | * Add the keyword flag to the mode selection.
686 | * This allows for matching emails with the given keyword.
687 | *
688 | * @param string $keyword The keyword to search for.
689 | *
690 | * @return Reader
691 | */
692 | public function keyword($keyword)
693 | {
694 | $this->modes[] = 'KEYWORD "' . $keyword . '"';
695 |
696 | return $this;
697 | }
698 |
699 | /**
700 | * Add the unkeyword flag to the mode selection.
701 | * This allows for matching emails without the given keyword.
702 | *
703 | * @param string $keyword The keyword to avoid.
704 | *
705 | * @return Reader
706 | */
707 | public function unkeyword($keyword)
708 | {
709 | $this->modes[] = 'UNKEYWORD "' . $keyword . '"';
710 |
711 | return $this;
712 | }
713 |
714 | /**
715 | * Add the before date flag to the mode selection.
716 | * This allows for matching emails received before the given date.
717 | *
718 | * @param string $date The date to match.
719 | *
720 | * @return Reader
721 | */
722 | public function beforeDate($date)
723 | {
724 | $date = date('d-M-Y', strtotime($date));
725 |
726 | $this->modes[] = 'BEFORE "' . $date . '"';
727 |
728 | return $this;
729 | }
730 |
731 | /**
732 | * Add the since date flag to the mode selection.
733 | * This allows for matching emails received since the given date.
734 | *
735 | * @param string $date The date to match.
736 | *
737 | * @return Reader
738 | */
739 | public function sinceDate($date)
740 | {
741 | $date = date('d-M-Y', strtotime($date));
742 |
743 | $this->modes[] = 'SINCE "' . $date . '"';
744 |
745 | return $this;
746 | }
747 |
748 | /**
749 | * Add the sent to flag to the mode selection.
750 | * This allows for matching emails sent to the given email address string.
751 | *
752 | * @param string $to The email address to match.
753 | *
754 | * @return Reader
755 | */
756 | public function sentTo($to)
757 | {
758 | $this->modes[] = 'TO "' . $to . '"';
759 |
760 | return $this;
761 | }
762 |
763 | /**
764 | * Add the BCC flag to the mode selection.
765 | * This allows for matching emails with the string present in the BCC field.
766 | *
767 | * @param string $to The email address to match.
768 | *
769 | * @return Reader
770 | */
771 | public function searchBCC($to)
772 | {
773 | $this->modes[] = 'BCC "' . $to . '"';
774 |
775 | return $this;
776 | }
777 |
778 | /**
779 | * Add the CC flag to the mode selection.
780 | * This allows for matching emails with the string present in the CC field.
781 | *
782 | * @param string $to The email address to match.
783 | *
784 | * @return Reader
785 | */
786 | public function searchCC($to)
787 | {
788 | $this->modes[] = 'CC "' . $to . '"';
789 |
790 | return $this;
791 | }
792 |
793 | /**
794 | * Add the on date flag to the mode selection.
795 | * This allows for matching emails received on the given date.
796 | *
797 | * @param string $date The date to match.
798 | *
799 | * @return Reader
800 | */
801 | public function onDate($date)
802 | {
803 | $date = date('d-M-Y', strtotime($date));
804 |
805 | $this->modes[] = 'ON "' . $date . '"';
806 |
807 | return $this;
808 | }
809 |
810 | /**
811 | * Add the text flag to the mode selection.
812 | * This allows for matching emails with the given text string.
813 | *
814 | * @param string $string The string to search for.
815 | *
816 | * @return Reader
817 | */
818 | public function searchText($string)
819 | {
820 | $this->modes[] = 'TEXT "' . $string . '"';
821 |
822 | return $this;
823 | }
824 |
825 | /**
826 | * Set the limit.
827 | * This can be used with page() for pagination of emails.
828 | *
829 | * @param int $limit The total number of emails to return.
830 | *
831 | * @return Reader
832 | */
833 | public function limit($limit)
834 | {
835 | $this->limit = (int) $limit;
836 |
837 | return $this;
838 | }
839 |
840 | /**
841 | * Set the page number.
842 | * This is used with limit() for pagination of emails.
843 | *
844 | * @param int $page The page number.
845 | *
846 | * @return Reader
847 | */
848 | public function page($page)
849 | {
850 | $this->page = $page;
851 |
852 | $this->offset = ($page - 1) * $this->limit;
853 |
854 | return $this;
855 | }
856 |
857 | /**
858 | * Set the email fetching order to ASCending.
859 | *
860 | * @return Reader
861 | */
862 | public function orderASC()
863 | {
864 | $this->order = 'ASC';
865 |
866 | return $this;
867 | }
868 |
869 | /**
870 | * Set the email fetching order to DESCending.
871 | *
872 | * @return Reader
873 | */
874 | public function orderDESC()
875 | {
876 | $this->order = 'DESC';
877 |
878 | return $this;
879 | }
880 |
881 | /**
882 | * Sets the folder to retrieve emails from. Alias for mailbox().
883 | *
884 | * @param string $folder The name of the folder. IE. INBOX.
885 | *
886 | * @return Reader
887 | */
888 | public function folder($folder)
889 | {
890 | return $this->mailbox($folder);
891 | }
892 |
893 | /**
894 | * Sets the mailbox to retrieve emails from.
895 | *
896 | * @param string $mailbox The name of the mailbox, IE. INBOX.
897 | *
898 | * @return Reader
899 | */
900 | public function mailbox($mailbox)
901 | {
902 | $this->mailbox = $mailbox;
903 |
904 | return $this;
905 | }
906 |
907 | /**
908 | * Get a formatted list of selected modes for imap_search.
909 | *
910 | * @return string
911 | */
912 | public function modes()
913 | {
914 | if (!$this->modes) {
915 | $this->modes[] = 'ALL';
916 | }
917 |
918 | return implode(' ', $this->modes);
919 | }
920 |
921 | /**
922 | * Fetch emails based on the previously set parameters.
923 | *
924 | * @return array
925 | */
926 | public function get()
927 | {
928 | if (!$this->connect()) {
929 | throw new Exception('ERROR: Could not connect.');
930 | }
931 |
932 | if ($this->id) {
933 | $this->emails = array();
934 |
935 | $this->emails[] = $this->getEmail($this->id);
936 |
937 | return $this->emails;
938 | }
939 |
940 | $this->emails = array();
941 |
942 | $this->email_index = imap_search(
943 | $this->stream(),
944 | $this->modes(),
945 | false,
946 | $this->encoding
947 | );
948 |
949 | if (!$this->limit) {
950 | $this->limit = isset($this->email_index) && is_array($this->email_index) ? count($this->email_index) : 0;
951 | }
952 |
953 | if ($this->email_index) {
954 | if ($this->order == 'DESC') {
955 | rsort($this->email_index);
956 | } else {
957 | sort($this->email_index);
958 | }
959 |
960 | if ($this->limit || ($this->limit && $this->offset)) {
961 | $this->email_index = array_slice(
962 | $this->email_index,
963 | $this->offset,
964 | $this->limit
965 | );
966 | }
967 |
968 | $this->emails = array();
969 |
970 | foreach ($this->email_index as $id) {
971 | $this->emails[] = $this->getEmailByMessageSequence($id);
972 |
973 | if ($this->mark_as_read) {
974 | $this->markAsRead($id);
975 | }
976 | }
977 | }
978 |
979 | return $this->emails;
980 | }
981 |
982 | /**
983 | * Fetches an email by its UID.
984 | *
985 | * @param integer $uid UID Number
986 | *
987 | * @return Email
988 | */
989 | public function getEmailByUID($uid)
990 | {
991 | return $this->getEmail($uid);
992 | }
993 |
994 | /**
995 | * Fetches an email by its message sequence id
996 | *
997 | * @param integer $id ID
998 | *
999 | * @return Email
1000 | */
1001 | public function getEmailByMessageSequence($id)
1002 | {
1003 | $uid = imap_uid($this->stream(), $id);
1004 |
1005 | return $this->getEmail($uid);
1006 | }
1007 |
1008 | /**
1009 | * Fetch an email by id.
1010 | *
1011 | * @param integer $uid The message UID.
1012 | *
1013 | * @return Email
1014 | */
1015 | public function getEmail($uid)
1016 | {
1017 | $email = new Email();
1018 |
1019 | // imap_headerinfo doesn't work with the uid, so we use imap_fetchbody instead.
1020 | //$header = imap_headerinfo($this->stream(), $uid);
1021 |
1022 | $options = ($this->mark_as_read) ? FT_UID : FT_UID | FT_PEEK;
1023 |
1024 | $header_from_body = imap_fetchbody($this->stream(), $uid, '0', $options);
1025 |
1026 | $header = imap_rfc822_parse_headers($header_from_body);
1027 |
1028 | if (!$header) {
1029 | return null;
1030 | }
1031 |
1032 | $email->setId($uid);
1033 |
1034 | $header->subject = isset($header->subject)
1035 | ? $this->decodeMimeHeader($header->subject)
1036 | : false;
1037 |
1038 | $email->setSubject($header->subject);
1039 |
1040 | $email->setDate(isset($header->date) ? $header->date : null);
1041 |
1042 | if (isset($header->to)) {
1043 | foreach ($header->to as $to) {
1044 | $to_name = isset($to->personal)
1045 | ? $this->decodeMimeHeader($to->personal)
1046 | : false;
1047 | $email->addTo($to->mailbox, $to->host, $to_name);
1048 | }
1049 | }
1050 |
1051 | if (isset($header->from)) {
1052 | $from_name = isset($header->from[0]->personal)
1053 | ? $this->decodeMimeHeader($header->from[0]->personal)
1054 | : false;
1055 | $email->setFrom(
1056 | $header->from[0]->mailbox,
1057 | $header->from[0]->host,
1058 | $from_name
1059 | );
1060 | }
1061 |
1062 | if (isset($header->reply_to)) {
1063 | foreach ($header->reply_to as $reply_to) {
1064 | $reply_to_name = isset($reply_to->personal)
1065 | ? $this->decodeMimeHeader($reply_to->personal)
1066 | : false;
1067 | $email->addReplyTo(
1068 | $reply_to->mailbox,
1069 | $reply_to->host,
1070 | $reply_to_name
1071 | );
1072 | }
1073 | }
1074 |
1075 | if (isset($header->cc)) {
1076 | foreach ($header->cc as $cc) {
1077 | $cc_name = isset($cc->personal)
1078 | ? $this->decodeMimeHeader($cc->personal)
1079 | : false;
1080 | $email->addCC($cc->mailbox, $cc->host, $cc_name);
1081 | }
1082 | }
1083 |
1084 | $email->setRawBody(imap_fetchbody($this->stream(), $uid, '', $options));
1085 |
1086 | $body = imap_fetchstructure($this->stream(), $uid, FT_UID);
1087 |
1088 | if (isset($body->parts) && count($body->parts)) {
1089 | foreach ($body->parts as $part_number => $part) {
1090 | $this->decodePart($email, $part, $part_number + 1);
1091 | }
1092 | } else {
1093 | $this->decodePart($email, $body);
1094 | }
1095 |
1096 | $msgno = imap_msgno($this->stream(), $uid);
1097 |
1098 | $email->setMsgno($msgno);
1099 |
1100 | $header = imap_headerinfo($this->imap, $msgno, 20, 20);
1101 |
1102 | $email->setSize(isset($header->Size) ? $header->Size : 0);
1103 |
1104 | $email->setUdate(isset($header->udate) ? $header->udate : null);
1105 |
1106 | $recent = isset($header->Recent)
1107 | && ($header->Recent == 'R' || $header->Recent == 'N')
1108 | ? true
1109 | : false;
1110 | $email->setRecent($recent);
1111 |
1112 | $unseen = isset($header->Unseen) && $header->Unseen == 'U'
1113 | ? true : false;
1114 | $email->setUnseen($unseen);
1115 |
1116 | $flagged = isset($header->Flagged) && $header->Flagged == 'F'
1117 | ? true : false;
1118 | $email->setFlagged($flagged);
1119 |
1120 | $answered = isset($header->Answered) && $header->Answered == 'A'
1121 | ? true : false;
1122 | $email->setAnswered($answered);
1123 |
1124 | $deleted = isset($header->Deleted) && $header->Deleted == 'D'
1125 | ? true : false;
1126 | $email->setDeleted($deleted);
1127 |
1128 | $draft = isset($header->Draft) && $header->Draft == 'X'
1129 | ? true : false;
1130 | $email->setDraft($draft);
1131 |
1132 | $headers = imap_fetchheader($this->stream(), $email->msgno());
1133 |
1134 | if ($headers) {
1135 |
1136 | $headers_array = explode("\n", imap_fetchheader($this->stream(), $email->msgno()));
1137 |
1138 | foreach ($headers_array as $header) {
1139 | if (strpos($header, "X-") !== false) {
1140 | $email->addCustomHeader($header);
1141 | }
1142 | }
1143 | }
1144 |
1145 | return $email;
1146 | }
1147 |
1148 | /**
1149 | * Decode an email part.
1150 | *
1151 | * @param Email $email The email object to update.
1152 | * @param object $part The part data to decode.
1153 | * @param boolean $part_number The part number.
1154 | *
1155 | * @return string
1156 | */
1157 | public function decodePart(Email $email, $part, $part_number = false)
1158 | {
1159 | $options = ($this->mark_as_read) ? FT_UID : FT_UID | FT_PEEK;
1160 |
1161 | if ($part_number) {
1162 | $data = imap_fetchbody(
1163 | $this->stream(),
1164 | $email->id(),
1165 | $part_number,
1166 | $options
1167 | );
1168 | } else {
1169 | $data = imap_body($this->stream(), $email->id(), $options);
1170 | }
1171 |
1172 | switch ($part->encoding) {
1173 | case 1:
1174 | $data = imap_utf8($data);
1175 | break;
1176 |
1177 | case 2:
1178 | $data = imap_binary($data);
1179 | break;
1180 |
1181 | case 3:
1182 | $data = imap_base64($data);
1183 | break;
1184 |
1185 | case 4:
1186 | $data = quoted_printable_decode($data);
1187 | break;
1188 | }
1189 |
1190 | $params = array();
1191 | if (isset($part->parameters)) {
1192 | foreach ($part->parameters as $param) {
1193 | $params[strtolower($param->attribute)] = $param->value;
1194 | }
1195 | }
1196 |
1197 | if (isset($part->dparameters)) {
1198 | foreach ($part->dparameters as $param) {
1199 | $params[strtolower($param->attribute)] = $param->value;
1200 | }
1201 | }
1202 |
1203 | // is this part an attachment
1204 | $attachment_id = false;
1205 | $is_attachment = false;
1206 |
1207 | if (
1208 | isset($part->disposition)
1209 | && in_array(strtolower($part->disposition), array('attachment', 'inline'))
1210 | && $part->subtype != 'PLAIN'
1211 | ) {
1212 | $is_attachment = true;
1213 | $attachment_type = strtolower($part->disposition);
1214 |
1215 | if ($attachment_type == 'inline') {
1216 | $is_inline_attachment = true;
1217 | $attachment_id = isset($part->id) ? trim($part->id, " <>") : false;
1218 | } else {
1219 | $is_inline_attachment = false;
1220 | $attachment_id = rand();
1221 | }
1222 | }
1223 |
1224 | // if there is an attachment
1225 | if ($is_attachment) {
1226 | $file_name = false;
1227 |
1228 | if (isset($params['filename'])) {
1229 | $file_name = $params['filename'];
1230 | } elseif (isset($params['name'])) {
1231 | $file_name = $params['name'];
1232 | }
1233 |
1234 | if ($file_name) {
1235 | $file_name = $attachment_id . '-' . $file_name;
1236 |
1237 | $attachment = new EmailAttachment();
1238 | $attachment->setId($attachment_id);
1239 | $attachment->setName($file_name);
1240 |
1241 | if ($is_inline_attachment) {
1242 | $attachment->setType('inline');
1243 | } else {
1244 | $attachment->setType('attachment');
1245 | }
1246 |
1247 | if ($this->save_attachments) {
1248 | $attachment->setFilePath(
1249 | $this->attachment_dir . DIRECTORY_SEPARATOR . $attachment->name()
1250 | );
1251 |
1252 | if ($this->attachment_dir && $attachment->filePath()) {
1253 | if (!file_exists($attachment->filePath())) {
1254 | file_put_contents($attachment->filePath(), $data);
1255 | }
1256 | }
1257 | } else {
1258 | $attachment->setAttachmentData($data);
1259 | }
1260 |
1261 | $email->addAttachment($attachment);
1262 | }
1263 | } else {
1264 | // if the charset is set, convert to our encoding UTF-8
1265 | if (!empty($params['charset'])) {
1266 | $data = $this->convertEncoding($data, $params['charset']);
1267 | }
1268 |
1269 | // part->type = 0 is TEXT or TYPETEXT
1270 | if (isset($part->type)) {
1271 | if ($part->type == 0) {
1272 | // subpart is either plain text or html version
1273 | if (strtoupper($part->subtype) == 'PLAIN') {
1274 | $email->setPlain($data);
1275 | } else {
1276 | $email->setHTML($data);
1277 | }
1278 |
1279 | // part->type = 2 is MESSAGE
1280 | } elseif ($part->type == 2) {
1281 | $email->setPlain($data);
1282 | }
1283 | }
1284 | }
1285 |
1286 | // rerun for additional parts
1287 | if (!empty($part->parts)) {
1288 | foreach ($part->parts as $subpart_number => $subpart) {
1289 | if ($part->type == 2 && $part->subtype == 'RFC822') {
1290 | $this->decodePart($email, $subpart, $part_number);
1291 | } else {
1292 | $this->decodePart($email, $subpart, $part_number . '.' . ($subpart_number + 1));
1293 | }
1294 | }
1295 | }
1296 |
1297 | return trim($data);
1298 | }
1299 |
1300 | /**
1301 | * Decode Mime Header.
1302 | *
1303 | * @param string $encoded_header The encoded header string.
1304 | *
1305 | * @return string
1306 | */
1307 | public function decodeMimeHeader($encoded_header)
1308 | {
1309 | $decoded_header = '';
1310 |
1311 | $elements = imap_mime_header_decode($encoded_header);
1312 |
1313 | for ($i = 0; $i < count($elements); $i++) {
1314 | if ($elements[$i]->charset == 'default') {
1315 | $elements[$i]->charset = 'iso-8859-1';
1316 | }
1317 |
1318 | $decoded_header .= $this->convertEncoding($elements[$i]->text, $elements[$i]->charset);
1319 | }
1320 |
1321 | return $decoded_header;
1322 | }
1323 |
1324 | /**
1325 | * Convert a string encoding to the encoding set.
1326 | *
1327 | * @param string $string The string to re-encode.
1328 | * @param string $current_encoding_type The encoding type of the original string.
1329 | *
1330 | * @return string
1331 | */
1332 | public function convertEncoding($string, $current_encoding_type)
1333 | {
1334 | $converted_string = false;
1335 |
1336 | if (!$string) {
1337 | return $string;
1338 | }
1339 |
1340 | if ($current_encoding_type == $this->encoding) {
1341 | return $string;
1342 | }
1343 |
1344 | if (extension_loaded('mbstring')) {
1345 | $converted_string = @mb_convert_encoding($string, $this->encoding, $current_encoding_type);
1346 | } else {
1347 | $converted_string = @iconv($current_encoding_type, $this->encoding . '//IGNORE', $string);
1348 | }
1349 |
1350 | return $converted_string ?: $string;
1351 | }
1352 | }
1353 |
--------------------------------------------------------------------------------