Сборщик писем по imap протоколу

Категория: Решение задач | Скилл: php , imap | Дата: 31.01.2020
Задача: собрать исходники писем с почтовых ящиков и сохранить на сервере (локальном).

Средства реализации: php & curl

Репозиторий с исходным кодом решения задачи https://github.com/Byurrer/imap-mail-collector. Есть подробный readme, а код внутри прокомментирован.

Коротко алгоритм довольно прост:

  1. подключение к почтовому ящику через imap протокол,
  2. проход по всем директориям на ящике
  3. скачивание исходников писем и распределение по директориям, как на ящике
Рутину алгоритма нет смысла описывать, код достаточно прост и прокомментирован. Лучше расскажу о проблемах, которые возникли в ходе решения.

Директории

Первая проблема заключалась в получении, разборе и использовании названий директорий на почтовом ящике. При авторизации на imap сервере в ответе будет получен список директорий на ящике в UTF7-IMAP (https://ru.wikipedia.org/wiki/UTF-7) кодировке:

* LIST (\Unmarked \HasNoChildren \Drafts) "|" Drafts
* LIST (\Unmarked \NoInferiors) "|" INBOX
* LIST (\Unmarked \HasNoChildren) "|" Outbox
* LIST (\Unmarked \HasNoChildren \Sent) "|" Sent
* LIST (\Unmarked \HasNoChildren \Junk) "|" Spam
* LIST (\Unmarked \HasNoChildren \Trash) "|" Trash

Нет проблем пока не появляются директории на кириллице с пробелами (название синтетическое для примера):

* LIST (\Trash) "/" "&BBoEPgRABDcEOAQ9BDA- &BBoEPgRABDcEOAQ9BDA-"

При попытке сканирования такой директории (по адресу: imaps://imap.domain.zone/&BBoEPgRABDcEOAQ9BDA- &BBoEPgRABDcEOAQ9BDA-/), imap сервер выдал: imap URL using bad/illegal format or missing URL

Как видно проблема в недопустимых символах, решение нашлось здесь, надо было просто экранировать эту часть url (название директории) при помощи curl_escape.

Декодировать строку можно так:

$sDir = mb_convert_encoding($value, "UTF-8", "UTF7-IMAP");

Кодировка

Исходник письма может быть в любой кодировке.

Изначально требовалось чтобы скрипт отправлял исходник письма и некоторые другие данные на другой сервер, для этого данные паковал json_encode, пока не пошли письма в windows-1251 кодировке, на что json_encode сказал: Malformed UTF-8 characters, possibly incorrectly encoded

Проблема была решена при помощи base64_encode исходника письма с последующим json_encode, а принимающий сервер делал обратные операции в обратном порядке и получал неизменные данные.

Удаление писем

Удалять письма надо по убыванию порядковых номеров (письмо с номером 1 удалять самым последним), иначе обратный порядок может привести к тому что порядковые номера при удалении будут изменены на imap сервере, а дальше неверная идентификация писем.

Если речь идет о последовательном удалении, тогда для этого (после получения и парсинга ответа после SEARCH ALL UNDELETED) можно просто применить arsort к массиву с порядковыми номерами:
//получение порядковых номеров всех неудаленных писем в директории
curl_setopt($hCurl, CURLOPT_URL, "$sImap/$value");
curl_setopt($hCurl, CURLOPT_CUSTOMREQUEST, "SEARCH ALL UNDELETED");
$sResponse = curl_exec($hCurl);

$sResponse = str_replace("\r\n", "\n", $sResponse);
$sResponse = mb_substr($sResponse, mb_strlen("* SEARCH "));

//парсим строку извлекая порядковые номера сообщений в директории
$aStrs = explode(" ", $sResponse);

//сортировка массива по убыванию, чтобы удалять не сбивая порядковые номера
arsort($aStrs);
Я Виталий, ник в сети Byurrer.
Увлекаюсь программированием, веду интересные проекты, пишу здесь об интересующих меня вещах: о работе, проектах, увлечениях и проффесиональном развитии.

Скилы
php, c++, javascript, sql, hlsl, html, css
Проекты
SkyXEngine, PHP-API, S4G
Категории
В разработке :)
Популярное
В разработке :)