Trois causes racines révélées par une vraie synchro complète (139 dossiers) : - contrainte UNIQUE globale sur message_id : fausse pour IMAP (un même Message-ID existe dans plusieurs dossiers) → violation → fermeture de l'EntityManager → cascade qui tuait tous les dossiers suivants. Migration : index simple à la place. - 139 connexions IMAP (une par dossier) → throttling OVH (failed to authenticate) : réutilisation d'une seule connexion (closeConnection() ajouté à l'interface). - état de connexion corrompu après un dossier en erreur (must be in SELECTED state) : reconnexion ciblée après chaque dossier en échec. - garde anti-cascade : reset du ManagerRegistry + arrêt propre si l'EM se ferme. Résultat : 456 messages sur 57 dossiers (avant : 188/30 puis crash). Les rares dossiers à encodage spécial sont skippés proprement et réessayés au cycle suivant. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
82 lines
2.3 KiB
PHP
82 lines
2.3 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Mail;
|
|
|
|
use App\Mail\Dto\MailFolderDto;
|
|
use App\Mail\Dto\MailMessageDetailDto;
|
|
use App\Mail\Dto\MailMessageHeaderDto;
|
|
use App\Mail\Exception\MailProviderException;
|
|
|
|
interface MailProviderInterface
|
|
{
|
|
/**
|
|
* Opens a connection using the stored configuration and returns the number
|
|
* of folders found. Used by the admin "test connection" endpoint, so it
|
|
* MUST work even when the configuration is not yet enabled.
|
|
*
|
|
* @throws MailProviderException
|
|
*/
|
|
public function testConnection(): int;
|
|
|
|
/**
|
|
* Releases any reused network connection held by the provider.
|
|
* Safe to call multiple times; a no-op if nothing is open.
|
|
*/
|
|
public function closeConnection(): void;
|
|
|
|
/**
|
|
* Returns the full folder tree of the configured mailbox.
|
|
*
|
|
* @return list<MailFolderDto>
|
|
*
|
|
* @throws MailProviderException
|
|
*/
|
|
public function listFolders(): array;
|
|
|
|
/**
|
|
* Returns a paginated list of message headers for the given folder.
|
|
*
|
|
* @return list<MailMessageHeaderDto>
|
|
*
|
|
* @throws MailProviderException
|
|
*/
|
|
public function listMessages(string $folderPath, int $limit, int $offset): array;
|
|
|
|
/**
|
|
* Fetches the full message (headers + body + attachments list) by UID.
|
|
*
|
|
* @throws MailProviderException
|
|
*/
|
|
public function fetchMessage(string $folderPath, int $uid): MailMessageDetailDto;
|
|
|
|
/**
|
|
* Marks a message as read or unread on the IMAP server.
|
|
*
|
|
* @throws MailProviderException
|
|
*/
|
|
public function markRead(string $folderPath, int $uid, bool $read): void;
|
|
|
|
/**
|
|
* Marks a message as flagged (starred) or unflagged on the IMAP server.
|
|
*
|
|
* @throws MailProviderException
|
|
*/
|
|
public function markFlagged(string $folderPath, int $uid, bool $flagged): void;
|
|
|
|
/**
|
|
* Moves a message from one folder to another on the IMAP server.
|
|
*
|
|
* @throws MailProviderException
|
|
*/
|
|
public function moveMessage(string $folderPath, int $uid, string $targetFolder): void;
|
|
|
|
/**
|
|
* Fetches the raw binary content of an attachment by its MIME part number.
|
|
*
|
|
* @throws MailProviderException
|
|
*/
|
|
public function fetchAttachment(string $folderPath, int $uid, string $partNumber): string;
|
|
}
|