Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

setFetchAttachment(true) doesn't do anything if setFetchBody(false) #277

Closed
SDCRoman opened this issue Jan 16, 2020 · 4 comments
Closed
Labels

Comments

@SDCRoman
Copy link

I am fetchting the mails of a mailbox, which works great.
I need to display an information whether mails have an attachment.

For this I was using this code, which WORKED:

$aMessage = $selectedFolder->messages()->setFetchFlags(true)->setFetchAttachment(true)->setFetchBody(true)->leaveUnread()->limit(40, $highest_page)->get();

The Problem is the load times were bad. To fix this I set setFetchBody to false, which greatly improved the load time. I dont need the body in the overview anyway:

$aMessage = $selectedFolder->messages()->setFetchFlags(true)->setFetchAttachment(true)->setFetchBody(false)->leaveUnread()->limit(40, $highest_page)->get();

Now even with setFetchAttachment(true) the attachment information is lost.
$oMessage->hasAttachments() always returns false.

If I switch back setFetchBody to true it works.

setFetchAttachment does not seem to do anything.

What am I doing wrong?

@SDCRoman
Copy link
Author

I dont fully understand why, but if I include $oMessage->parseBody() into my response (eventhough I dont use it), then hasAttachments() returns the correct value. Ofcourse while setFetchBody(false).

Case one: The relevant line was commented out. In this case hasAttachments() was always false. The attachment information is not there.

//$result[$message_id]['raw'] = $oMessage->parseBody();
$result[$message_id]['hasAttachments'] = $oMessage->hasAttachments();

Case two: The relevant line is present. In this case hasAttachments() returns the correct value.

$result[$message_id]['raw'] = $oMessage->parseBody();
$result[$message_id]['hasAttachments'] = $oMessage->hasAttachments();

Well it seems my issue is solved, but I dont fully understand why. Just in case here is the whole code, which I use to loop through all messages in a mailbox and build my respose:

// Get all messages of mailbox
if ($data->type == "initial") {
    $highest_page = 1;
} else {
    $highest_page = $data->page;
}

$result = array(); 

if ($data->search_term == "") {
    $aMessage = $selectedFolder->messages()->setFetchFlags(true)->setFetchBody(false)->setFetchAttachment(true)->leaveUnread()
    ->limit(40, $highest_page)->get();
} else {         
    $aMessage = $selectedFolder->messages()->text($data->search_term)->setFetchFlags(true)->setFetchBody(false)->setFetchAttachment(true)->leaveUnread()
    ->limit(40, $highest_page)->get();                    
}

foreach($aMessage as $oMessage) {
        
    if (strpos(strtolower($oMessage->getMessageId()), "?utf-8?")) {
        $message_id = mb_decode_mimeheader($oMessage->getMessageId());
    } else {
        $message_id = $oMessage->getMessageId();
    }

    // NOTE: God knows why, but I need to INCLUDE this in the response if setFetchBody(false), otherwise hasAttachments is always false.
    $result[$message_id]['raw'] = $oMessage->parseBody();

    $result[$message_id]['hasAttachments'] = $oMessage->hasAttachments();

    //$result[$oMessage->getMessageId()]['headerInfo'] = $oMessage->getHeaderInfo();
    $result[$message_id]['MailDate'] = $oMessage->getDate();

    $result[$message_id]['MailDateTimestamp'] = $oMessage->getDate()->timestamp;

    $result[$message_id]['uID'] = $oMessage->getUid();

    $result[$message_id]['Seen'] = $oMessage->getFlags()['seen'];
    
    if (strpos(strtolower($oMessage->getFrom()[0]->mail), "?utf-8?")) {
        $result[$message_id]['fromMail'] = mb_decode_mimeheader($oMessage->getFrom()[0]->mail);
    } else {
        $result[$message_id]['fromMail'] = $oMessage->getFrom()[0]->mail;
    }

    if ($oMessage->getTo()) {
        if (strpos(strtolower($oMessage->getTo()[0]->mail), "?utf-8?")) {
            $result[$message_id]['toMail'] = mb_decode_mimeheader($oMessage->getTo()[0]->mail);
        } else {
            $result[$message_id]['toMail'] = $oMessage->getTo()[0]->mail;
        }
    } else {
        $result[$message_id]['toMail'] = "Unknown";
    }      
    
    if (strpos(strtolower($oMessage->getSubject()), "?utf-8?")) {
        $result[$message_id]['subject'] = mb_decode_mimeheader($oMessage->getSubject());
    } else {
        $result[$message_id]['subject'] = $oMessage->getSubject(); 
    }

    // Leave uncommented, because if attachments are retrieved they cannot be parsed to JSON:
    // https://github.com/Webklex/laravel-imap/issues/63
    //$result[$message_id]['all'] = $oMessage;
    $result[$message_id]['getStructure'] = $oMessage->getStructure();

}

@Webklex
Copy link
Owner

Webklex commented Jan 23, 2020

Hi @SDCRoman ,
in order to fetch the attachmenets you have to fetch the body first.
If you take a look at a raw message you'll notice that the attachments are part of the body.

Kind Regards

@SDCRoman
Copy link
Author

SDCRoman commented Jan 24, 2020

But I am not fetching the body in the working example. In theory it should not work, but it does.

I dont fully understand why, but if I include $oMessage->parseBody() into my response (eventhough I dont use it), then hasAttachments() returns the correct value. Ofcourse while setFetchBody(false)

Well. I ditched the hasAttachments() check because it does not work for me. I must use setFetchBody(false) while I fetch the messages, because this tremendously improves performance (for me from 30 sec+ timeout to 4 sec). But with setFetchBody(false) the attachment information was lost (hasAttachments() always returned false). I had to include $oMessage->parseBody() into my response (AJAX), but now I encountered the next error for some mails: Malformed UTF-8 characters. This error appears if I include the parsed body into my response, because for AJAX attachment contents cannot be utf8 encoded.

I understand now that the attachment information is in the body. I still dont understand why parseBody() returns the attachment information if setFetchBody(false). I feel like something is weird here, but maybe I just dont get it.

I found a better way to check for attachments. I dont include the whole parsed body into the response. I check in the server whether the attachment array in the parsed body has a greater length then 0. So far everything seems to work for me:

$hasAttachments = false;
if (count($oMessage->parseBody()->attachments) > 0) {
    $hasAttachments = true;
}

$result[$message_id]['hasAttachments'] = $hasAttachments;

@Webklex
Copy link
Owner

Webklex commented Sep 22, 2020

Please update to v2.0.0 :)

@Webklex Webklex closed this as completed Sep 22, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants