php-imap
php-imap copied to clipboard
Move message fails silently
Move message fails silently.
$messagge->move('INBOX.Trash'); // fails silently.
Here is the why:
move method at https://github.com/Webklex/php-imap/blob/master/src/Message.php#L901 does
$status = $this->client->getConnection()->examineFolder($folder_path);
if (isset($status["uidnext"])) {
but, "uidnext" does no exists for me.
dd($this->client->getConnection()->examineFolder('INBOX.Trash'));
array:4 [
"flags" => array:1 [
0 => array:6 [
0 => "\Draft"
1 => "\Answered"
2 => "\Flagged"
3 => "\Deleted"
4 => "\Seen"
5 => "\Recent"
]
]
"exists" => "1"
"recent" => "0"
"uidvalidity" => 1444046641
]
Now next line is 917:
return null;
That lets me wondering what just happened that message was not moved and no exception was raised. :)
Hi @EthraZa , thanks for your report.
This is actually intended - Providers such as Microsoft do their own little thing and don't provide the next uid. The message should be moved regardless. There is just no way to find out were it went after it got moved...
Best regards,
Hi. This is my own very old mail server running Postfix and Courier imap. :)
The message is not being moved at all, because it is not passing by the IF statement.
public function move($folder_path, $expunge = false) {
$this->client->openFolder($folder_path);
$status = $this->client->getConnection()->examineFolder($folder_path);
if (isset($status["uidnext"])) { // <-- YOU SHALL NOT PASS
// Would Move Message Here
}
return null;
}
To it to move the message the IF would need to be something like:
if (isset($status["uidnext"]) || isset($status["uidvalidity"])) {
$next_uid = $status["uidnext"] ?? $status["uidvalidity"];
I just don't know if you can simple replace "uidnext" with "uidvalidity" at $next_uid.
Hi @EthraZa , haha, sorry my bad :)
I'll look into it. I don't think uidvalidity
will work - isn't that just the highest possible uid?
Best regards,
According to https://www.php.net/manual/en/function.imap-status.php:
SA_UIDNEXT - set $status->uidnext to the next uid to be used in the mailbox
SA_UIDVALIDITY - set $status->uidvalidity to a constant that changes when uids for the mailbox may no longer be valid
But I see that the moveMessage don't need it to happen, it will be used only on fetchNewMail. I'm not sure why fetchNewMail is needed there, at move and copy methods, so I can't opine on how to solve this.
Yes you are right! Could you test it?
Update Message::class
@ Line 901-918:
public function move($folder_path, $expunge = false, $fetch_new = true) {
$this->client->openFolder($folder_path);
/** @var Folder $folder */
$folder = $this->client->getFolderByPath($folder_path);
$this->client->openFolder($this->folder_path);
if ($this->client->getConnection()->moveMessage($folder->path, $this->getSequenceId(), null, $this->sequence === IMAP::ST_UID) == true) {
if ($fetch_new) {
$status = $this->client->getConnection()->examineFolder($folder_path);
if (isset($status["uidnext"])) {
return $this->fetchNewMail($folder, $status["uidnext"], "moved", $expunge);
}
return null;
}
return true;
}
return $fetch_new ? null : false;
}
...and call:
$check = $message->move("INBOX.somewhere", false, false);
Best regards,
Didn't work.
...
$this->client->openFolder($this->folder_path);
dd([$this->client->getConnection()->moveMessage($folder->path, $this->getSequenceId(), null, $this->sequence === IMAP::ST_UID), $folder->path, $this->getSequenceId(), null, $this->sequence === IMAP::ST_UID]);
if (...
^ array:5 [
0 => false
1 => "INBOX.Trash"
2 => 3
3 => null
4 => false
]
The moveMessage itself is returning false (at 0).
ImapProtocol.php / moveMessage:
dd([$this->requestAndResponse($command, [$set, $this->escapeString($folder)], true), $command, $set, $folder]);
^ array:4 [
0 => false
1 => "MOVE"
2 => 3
3 => "INBOX.Trash"
]
ImapProtocol.php / requestAndResponse:
dd([$this->sendRequest($command, $tokens, $tag), $this->readResponse($tag, $dontParse), $command, $tokens, $tag, $dontParse]);
$command == anything
^ array:6 [
0 => null
1 => true
2 => "LOGIN"
3 => array:2 [
0 => ""EMAIL@DOMAIN""
1 => ""PASSWORD""
]
4 => "TAG1"
5 => true
]
^ array:6 [
0 => null
1 => array:1 [
0 => "BYE Courier-IMAP server shutting down\r\n"
]
2 => "LOGOUT"
3 => []
4 => "TAG2"
5 => true
]
$command == "MOVE"
^ array:6 [
0 => null
1 => false
2 => "MOVE"
3 => array:2 [
0 => 3
1 => ""INBOX.Trash""
]
4 => "TAG18"
5 => true
]
Hi @EthraZa , thanks for the detailed dumps. Unfortunately I don't see the problem which could cause this...
Could you provide me a limited test account, so I can "play" with it over the weekend? If it is possible, please mail the details to [email protected].
Best regards,
Sure, just sent an email.
Thank you.
Hi @EthraZa , your mail never made it into my mailbox - if my mailserver rejected it, you've should have received a message :)
Best regards,
Just saw that and resent the email, now as my gmail account.
Hi @EthraZa, I'm running into an issue similar to yours, on an old on-premise Courier server.
move()
always fails; copy()
apparently is randomly failing.
Did you find any workaround?
Thanks
Hi. Unfortunately no. I had to move away from this old server. But in the new ones it's not that better, because of other problems I can't move or delete messages, I just set them as read and let other proccess move it.