Skip to content
Эта страница создана и переведена с помощью ИИ. Если вы заметили неточности, помогите нам улучшить её. Редактировать на GitHub

Конфигурация IMAP

PRX-Email подключается к IMAP-серверам через TLS с помощью библиотеки rustls. Поддерживается парольная аутентификация и XOAUTH2 для Gmail и Outlook. Синхронизация входящих основана на UID и является инкрементальной, с персистентностью курсора в SQLite-базе данных.

Базовая настройка IMAP

rust
use prx_email::plugin::{ImapConfig, AuthConfig};

let imap = ImapConfig {
    host: "imap.example.com".to_string(),
    port: 993,
    user: "[email protected]".to_string(),
    auth: AuthConfig {
        password: Some("your-app-password".to_string()),
        oauth_token: None,
    },
};

Поля конфигурации

ПолеТипОбязательноОписание
hostStringДаИмя хоста IMAP-сервера (не должно быть пустым)
portu16ДаПорт IMAP-сервера (обычно 993 для TLS)
userStringДаIMAP-пользователь (обычно адрес электронной почты)
auth.passwordOption<String>Одно изПароль приложения для IMAP LOGIN
auth.oauth_tokenOption<String>Одно изOAuth-токен доступа для XOAUTH2

Аутентификация

Должно быть установлено ровно одно из password или oauth_token. Установка обоих или ни одного приведёт к ошибке валидации.

Настройки распространённых провайдеров

ПровайдерХостПортМетод аутентификации
Gmailimap.gmail.com993Пароль приложения или XOAUTH2
Outlook / Office 365outlook.office365.com993XOAUTH2 (рекомендуется)
Yahooimap.mail.yahoo.com993Пароль приложения
Fastmailimap.fastmail.com993Пароль приложения
ProtonMail Bridge127.0.0.11143Пароль Bridge

Синхронизация входящих

Метод sync подключается к IMAP-серверу, выбирает папку, получает новые сообщения по UID и сохраняет их в SQLite:

rust
use prx_email::plugin::SyncRequest;

plugin.sync(SyncRequest {
    account_id: 1,
    folder: Some("INBOX".to_string()),
    cursor: None,        // Продолжить с последнего сохранённого курсора
    now_ts: now,
    max_messages: 100,   // Получить не более 100 сообщений за синхронизацию
})?;

Процесс синхронизации

mermaid
sequenceDiagram
    participant Plugin as EmailPlugin
    participant DB as SQLite
    participant IMAP as IMAP Server

    Plugin->>DB: Load sync cursor for account/folder
    Plugin->>IMAP: TLS Connect + Login/XOAUTH2
    Plugin->>IMAP: SELECT folder
    Plugin->>IMAP: UID SEARCH (from cursor+1)
    IMAP-->>Plugin: UID list
    loop Each UID
        Plugin->>IMAP: UID FETCH (RFC822)
        IMAP-->>Plugin: Raw message
        Plugin->>Plugin: Parse MIME (headers, body, attachments)
        Plugin->>DB: UPSERT message
    end
    Plugin->>DB: Update sync cursor
    Plugin->>IMAP: LOGOUT

Инкрементальная синхронизация

PRX-Email использует UID-курсоры для предотвращения повторной выборки сообщений. После каждой синхронизации:

  1. Наибольший увиденный UID сохраняется как курсор
  2. Следующая синхронизация начинается с cursor + 1
  3. Сообщения с существующими парами (account_id, message_id) обновляются (UPSERT)

Курсор хранится в таблице sync_state с составным ключом (account_id, folder_id).

Синхронизация нескольких папок

Синхронизация нескольких папок для одного аккаунта:

rust
for folder in &["INBOX", "Sent", "Drafts", "Archive"] {
    plugin.sync(SyncRequest {
        account_id,
        folder: Some(folder.to_string()),
        cursor: None,
        now_ts: now,
        max_messages: 100,
    })?;
}

Планировщик синхронизации

Для периодической синхронизации используйте встроенный sync runner:

rust
use prx_email::plugin::{SyncJob, SyncRunnerConfig};

let jobs = vec![
    SyncJob { account_id: 1, folder: "INBOX".into(), max_messages: 100 },
    SyncJob { account_id: 1, folder: "Sent".into(), max_messages: 50 },
    SyncJob { account_id: 2, folder: "INBOX".into(), max_messages: 100 },
];

let config = SyncRunnerConfig {
    max_concurrency: 4,         // Макс. задач на тик планировщика
    base_backoff_seconds: 10,   // Начальный backoff при ошибке
    max_backoff_seconds: 300,   // Максимальный backoff (5 минут)
};

let report = plugin.run_sync_runner(&jobs, now, &config);
println!(
    "Run {}: attempted={}, succeeded={}, failed={}",
    report.run_id, report.attempted, report.succeeded, report.failed
);

Поведение планировщика

  • Ограничение конкурентности: не более max_concurrency задач на тик
  • Backoff при ошибках: экспоненциальный backoff по формуле base * 2^failures, ограниченный max_backoff_seconds
  • Проверка срока: задачи пропускаются, если их окно backoff ещё не истекло
  • Отслеживание состояния: для каждого ключа account::folder отслеживаются (next_allowed_at, failure_count)

Разбор сообщений

Входящие сообщения разбираются с помощью крейта mail-parser со следующим извлечением:

ПолеИсточникПримечания
message_idЗаголовок Message-IDРезерв: SHA-256 сырых байт
subjectЗаголовок Subject
senderПервый адрес из заголовка From
recipientsВсе адреса из заголовка ToРазделённые запятыми
body_textПервая часть text/plain
body_htmlПервая часть text/htmlРезерв: извлечение сырого раздела
snippetПервые 120 символов body_text или body_html
references_headerЗаголовок ReferencesДля группировки в цепочки
attachmentsMIME-части вложенийМетаданные в формате JSON

TLS

Все IMAP-подключения используют TLS через rustls с сертификатным пакетом webpki-roots. Нет возможности отключить TLS или использовать STARTTLS — подключения всегда шифруются с самого начала.

Следующие шаги

Released under the Apache-2.0 License.