Garethp / php-ews

PHP Exchange Web Services
BSD 3-Clause "New" or "Revised" License
112 stars 45 forks source link

How to get emails from subfolder that were received today #188

Closed l0ckm4 closed 4 years ago

l0ckm4 commented 4 years ago

I am new to this library but i have managed to use impersonation and connect the API to a subfolder of a users mailbox without too much issue using the following:-

require_once "/var/www/html/vendor/autoload.php";

use garethp\ews\API\Type;
use garethp\ews\MailAPI;

$host     = 'myserver';
$username = 'myusername';
$password = 'mypassword';

$api = MailAPI::withUsernameAndPassword($host, $username, $password, ['impersonation' => 'someoneelse@here.com']);
$folder = $api->getFolderByDisplayName('SystemsEmails',\garethp\ews\API\Enumeration\DistinguishedFolderIdNameType::INBOX);
$folderId = $folder->getfolderId();

$someemails = $api->getMailItems($folderId, [
    'IndexedPageItemView' => [
        'MaxEntriesReturned' => 100,
        'Offset' => 0,
        'BasePoint' => 'Beginning'
    ]
]);

print_r($someemails);

This works. If I try just $someemails = $api->getMailItems($folderId); then it errors due to the number of emails in the folder.

What I really need to do is to list either all emails from an email address (or by the subject) in that folder that was received that day. i.e. Use some additional filtering on date ranges/from and subject. Is that possible?

Thanks in advance

Garethp commented 4 years ago

What error do you get in regards to the mail count? Also, are you interested in getting emails within a certain date range, or getting new emails since the last time you checked?

l0ckm4 commented 4 years ago

Hi Gareth,

Thanks for the reply. Its the standard error relating to trying to retrieve more than 1000 emails - I am happy with the error message and I know I could look at the count from the folder to know if I need pagination or not. I have since figured out how to use pagination and loop through all and then break out by looking at received date but I would like to only retrieve emails for the current day and would like to be able to filter the request accordingly to avoid waste. An even better filter would be to use the subject.

Ideally I would like to know how to filter both on date ranges and/subject.

Thanks

Mark

Garethp commented 4 years ago

Well, searching by date is a little bit harder for mail items, but what you want to look into is applying Restrictions. There's some examples of it being used for other properties in this issue. I don't know if I have an active exchange account to test this, but you might want something like:

$someemails = $api->getMailItems($folderId, [
    'IndexedPageItemView' => [
        'MaxEntriesReturned' => 100,
        'Offset' => 0,
        'BasePoint' => 'Beginning'
    ],
    'Restriction' => [
            'IsEqualTo' => [
                'DateTimeCreated' => $dateTime->format('c')
            ]
        ]
    ]
]);

It's a bit different to the examples I have linked, but that's because there's a helper script for email restrictions to try and allow simpler constructions. I don't know if it'll work too well once you get to filtering on both subject and created date, but give this a try for created date and see if we can't figure that out first

l0ckm4 commented 4 years ago

Stunning!!! :-)

This returns messages after 11am this morning...

$datefilter = date("F d 11:00:00", strtotime('today'));
$date = new DateTime($datefilter);

$tmparr = $api->getMailItems($folderId, [
    'IndexedPageItemView' => [
        'MaxEntriesReturned' => 1000,
        'Offset' => 0,
        'BasePoint' => 'Beginning'
    ],
    'Restriction' => [
        'IsGreaterThan' => [
            'DateTimeReceived' => $date->format('c')
         ],
        //'IsEqualTo' => [
            //'Subject' => 'My Subject Goes Here'
        //]
    ]
]);

This returns the messages with the subject of 'My Subject Goes Here'

$datefilter = date("F d 11:00:00", strtotime('today'));
$date = new DateTime($datefilter);

$tmparr = $api->getMailItems($folderId, [
    'IndexedPageItemView' => [
        'MaxEntriesReturned' => 1000,
        'Offset' => 0,
        'BasePoint' => 'Beginning'
    ],
    'Restriction' => [
        // 'IsGreaterThan' => [
            // 'DateTimeReceived' => $date->format('c')
        // ],
        'IsEqualTo' => [
            'Subject' => 'My Subject Goes Here'
        ]
    ]
]);

This give me an error though

$datefilter = date("F d 11:00:00", strtotime('today'));
$date = new DateTime($datefilter);

$tmparr = $api->getMailItems($folderId, [
    'IndexedPageItemView' => [
        'MaxEntriesReturned' => 1000,
        'Offset' => 0,
        'BasePoint' => 'Beginning'
    ],
    'Restriction' => [
        'IsGreaterThan' => [
            'DateTimeReceived' => $date->format('c')
         ],
        'IsEqualTo' => [
            'Subject' => 'My Subject Goes Here'
        ]
    ]
]);

Any ideas?

Thanks for the help so far btw :-)

Garethp commented 4 years ago

What error are you getting?

l0ckm4 commented 4 years ago
PHP Fatal error:  Uncaught SoapFault exception: [a:ErrorSchemaValidation] The request failed schema validation: The element 'Restriction' in namespace 'http://schemas.microsoft.com/exchange/services/2006/messages' has invalid child element 'IsGreaterThan' in namespace 'http://schemas.microsoft.com/exchange/services/2006/types'. in /var/www/html/vendor/garethp/php-ews/src/API/NTLMSoapClient.php:118
Stack trace:
#0 /var/www/html/vendor/garethp/php-ews/src/API/NTLMSoapClient.php(118): SoapClient->__call('FindItem', Array)
#1 /var/www/html/vendor/garethp/php-ews/src/API/ExchangeWebServices/MiddlewareFactory.php(18): garethp\ews\API\NTLMSoapClient->__call('FindItem', Array)
#2 /var/www/html/vendor/garethp/php-ews/src/API/ExchangeWebServices.php(497): garethp\ews\API\ExchangeWebServices->garethp\ews\API\ExchangeWebServices\{closure}(Object(garethp\ews\API\MiddlewareRequest), Object(Closure))
#3 /var/www/html/vendor/garethp/php-ews/src/API/ExchangeWebServices/MiddlewareFactory.php(32): garethp\ews\API\ExchangeWebServices->garethp\ews in /var/www/html/vendor/garethp/php-ews/src/API/NTLMSoapClient.php on line 118
Garethp commented 4 years ago

I've just pushed an update to master. Can you make sure that you have the latest version from dev-master and try

$datefilter = date("F d 11:00:00", strtotime('today'));
$date = new DateTime($datefilter);

$tmparr = $api->getMailItems($folderId, [
    'IndexedPageItemView' => [
        'MaxEntriesReturned' => 1000,
        'Offset' => 0,
        'BasePoint' => 'Beginning'
    ],
    'Restriction' => [
        'And' => [
            'IsGreaterThan' => [
                'DateTimeReceived' => $date->format('c')
            ],
            'IsEqualTo' => [
                'Subject' => 'My Subject Goes Here'
            ]
        ]
    ]
]);
Garethp commented 4 years ago

Also, feel free to try some various combinations of restrictions. I wrote some test cases here, to give you an idea how to format your Restrictions. If things go well, I'll write up some examples and maybe make a new release for these features

l0ckm4 commented 4 years ago

HI Gareth,

That's great thank you. I have left for the day now but will look at it on Monday :-)

Cheers

l0ckm4 commented 4 years ago

Hi Gareth.

Success :-)

I have tried the various permutations which gave me the expected results:-

<?php
date_default_timezone_set('Europe/London');
require_once "/var/www/html/vendor/autoload.php";
use garethp\ews\API\Type;
use garethp\ews\MailAPI;

$host     = 'myserver';
$username = 'myusername';
$password = 'mypassword';

//Using Impersonation to get to another users mailbox
$api = MailAPI::withUsernameAndPassword(
    $host, 
    $username, 
    $password, 
    [
        'impersonation' => 'me@somehwere.com', 
        'timezone' => 'GMT Standard Time'
    ]);
$folder = $api->getFolderByDisplayName(
    'SystemsEmails',    
    \garethp\ews\API\Enumeration\DistinguishedFolderIdNameType::INBOX
);
$folderId = $folder->getfolderId();

$datefilter = date("F d 00:00:00", strtotime('today'));  //Get Today's Emails
$date = new DateTime($datefilter);

//Returns all emails today with subject being 'Testing 123'
$restriction = [
    'And' => [
        'IsGreaterThan' => [
            'DateTimeReceived' => $date->format('c')
        ],
        'IsEqualTo' => [
            'Subject' => 'Testing 123'
        ]
    ]
]; 
//Returns all emails today with subject being either  'This is a test' or 'Testing 123'
$restriction = [
    'And' => [
        'IsGreaterThan' => ['DateTimeCreated' => $date->format('c')],
        'Or' => [
            'IsEqualTo' => [
                ['Subject' => 'Testing 123'],
                ['Subject' => 'This is a test']
            ]
        ]
    ]
]; 

//Returns all emails today and any email that has subject 'Test' received at any time
$restriction = [
    'Or' => [
        'IsGreaterThan' => ['DateTimeCreated' => $date->format('c')],
        'And' => [
            'IsEqualTo' => [
                'Subject' => 'Test'
            ]
        ]
    ]
];

//Returns all emails today and any email that has subject 'Test' received at 
//any time which are unread
$restriction = [
    'Or' => [
        'IsGreaterThan' => ['DateTimeCreated' => $date->format('c')],
        'And' => [
            'IsEqualTo' => [
                'Subject' => 'Test', 'IsRead' => false
            ]
        ]
    ]
];  

//Returns all emails with any of the 3 subjects 
$restriction = [
    'Or' => [
        'IsEqualTo' => [
            ['Subject' => 'Testing 123'],
            ['Subject' => 'This is a test'],
            ['Subject' => 'Test']
        ]
    ]
];

$emails = array();

//Starting point for pagination
$i=0;

//Number of items to return in each iteration.  
//   If you expect less results then set it lower, if you expect more then 
//   set it higher - max value is 1000 for me.
$step = 50;  

//Do you need the body of the email too?
$getbody = true;  

do {
    $results = $api->getMailItems($folderId, [
        'IndexedPageItemView' => [
            'MaxEntriesReturned' => $step,
            'Offset' => $i,
            'BasePoint' => 'Beginning'
        ],
        'Restriction' => $restriction
    ]);
    foreach ($results as $z=>$a) {
        if ($getbody===true) {
            $mail = $api->getItem($a->getItemId()); 
            $emails[] = array(
                    'subject' => $a->getSubject(), 
                   'dateTimeReceived' => $a->getDateTimeReceived(), 
                   'Body' => (string) $mail->getBody()
            );
        } else {
            $emails[] = array(
                   'subject' => $a->getSubject(), 
                   'dateTimeReceived' => $a->getDateTimeReceived()
            );
        }
    }
    $i = $i+$step;
} while ($results->isIncludesLastItemInRange()===false);  //Loop until last page is returned

//print_r($results);
print_r($emails);  //here are the emails

Thank you so much for your prompt and comprehensive assistance. It is much appreciated.

Thanks

Mark

Garethp commented 4 years ago

Thanks for your help!