}`, the * server replies with a continuation request ("+"), and only then is the * message streamed back via {@see ResponseStream::respond()}. Returns the * assigned UID when the server reports APPENDUID (RFC 4315 / UIDPLUS), * otherwise null. * * @implements CommandInterface */ final class AppendCommand implements CommandInterface { private readonly ResponseCodeParser $responseCodeParser; private readonly string $literal; /** * @param list $flags optional initial flags, e.g. ['\\Seen'] */ public function __construct( private readonly string $mailbox, string $message, private readonly array $flags = [], ) { $this->responseCodeParser = new ResponseCodeParser(); // IMAP literals are octet-counted; normalise to CRLF line endings. $this->literal = (string) preg_replace('/\r\n|\r|\n/', "\r\n", $message); } public function name(): string { return 'APPEND'; } public function allowedStates(): array { return [SessionState::Authenticated, SessionState::Selected]; } public function encode(string $tag, SessionContext $context): RequestFrame { unset($tag, $context); $flagSegment = $this->flags === [] ? '' : '(' . implode(' ', $this->flags) . ') '; return new RequestFrame(sprintf( 'APPEND %s %s{%d}', StringEncoder::quote($this->mailbox), $flagSegment, strlen($this->literal), )); } public function handle(ResponseStream $responses, SessionContext $context): ?int { unset($context); foreach ($responses as $response) { if ($response instanceof ContinuationResponse) { // Continuation granted: stream the literal, then CRLF to end the command. $responses->respond($this->literal . "\r\n"); continue; } if ($response instanceof TaggedResponse) { if (!$response->isOk()) { throw new CommandFailedException( 'APPEND', $response->status(), $response->text(), $this->responseCodeParser->parse($response->text()), ); } return $this->parseAppendUid($response->text()); } } throw new ImapException('APPEND did not receive a tagged completion response.'); } private function parseAppendUid(string $text): ?int { $responseCode = $this->responseCodeParser->parse($text); if ($responseCode === null || $responseCode['name'] !== 'APPENDUID') { return null; } $arguments = $responseCode['arguments']; if (count($arguments) !== 2 || !ctype_digit($arguments[0]) || !ctype_digit($arguments[1])) { return null; } return (int) $arguments[1]; } }