Email backup. Выбираем архиватор почтовых сообщений.

Самохостятам привет!

Это сопроводительная тема к видео, которое выйдет в декабре-25.

1. Предыстория:

Вопросом

Было бы хорошо контролировать архив своей почты*, живущей в чужих облаках.
*Речь про 5-6 почтовых ящиков раскиданных по mail\yandex\google

я задался в начале лета 25 года и к моему удивления, я толком не нашел готовых продуктов. Само собой речь про open source & self hosted решения.
Нашлись только:

  • скрипты на питоне для выдергивания почты
  • да инструкции как во внешнего клиента скачать и сохранить в архив

Удивился, и ушел дальше своими делами заниматься.. аж до октября-25 года,
а там уже вышел ролик про Mail-Archiver от RomNero

2. Почему так мало такого open source & self hosted ПО? (как мне кажется)

  • мы перестали передавать нашу ценную личную информацию в email
    (telegram, cloud диски, google\apple photo)
  • а рабочую почту для нас бекапируют спец. сотрудники\сервисы

3. Так зачем и кому нужны эти архивы почты в 2025?

1. Тем у кого угоняли аккаунты\блокировали по ошибке учетки онлайн сервисов.
Даже в 2025 это случается и это больно.. Вот скажет завтра кто-то что Вам не доступен Ваш почтовый ящик 10-20 летний… Уверен, что будет сильно обидно..

2. Малому бизнесу.
Просто чтобы данные не потерялись, уволился сотрудник - убрали в архив, учетку удалили, не надо оплачивать.

3. Тем у кого много ящиков и нужно единое место для поиска
чтобы не бегать по ящикам

4. Какие сервисы ты знаешь в дек-25?

И вот тут, буквально спустя пол года с первого поиска - я увидел, что лед тронулся.
Некоторые сервисы появилось буквально неделю назад, какие-то месяц..

И теперь у нас есть возможность познакомиться с:

Я зачем-то(давно не спорю с душевными порывами) решил пойти не просто путем “посмотрим с вами репозитории и их скриншоты”, а полноценно развернуть, подключить почту и потестировать важные для меня пункты:

Я уверен, что кому-то будет важны такие вещи как поддержка SSO, роли для пользователей. Я постараюсь это раскрыть в видео, но в таблицу с Вашего позволения добавлять не стану.

5. Подсказки по установке

5.1 Mail-Archiver

5.1.1 Docker Compose из quick start с официального git-repo

docker-compose.yml
services:
  mailarchive-app:
    image: s1t5/mailarchiver:latest
    restart: always
    environment:
      # Database Connection
      - ConnectionStrings__DefaultConnection=Host=postgres;Database=MailArchiver;Username=mailuser;Password=masterkey;

      # Authentication Settings
      - Authentication__Username=admin
      - Authentication__Password=secure123!

      # TimeZone Settings
      - TimeZone__DisplayTimeZoneId=Etc/UCT
    ports:
      - "5000:5000"
    networks:
      - postgres
    volumes:
      - ./data-protection-keys:/app/DataProtection-Keys
    depends_on:
      postgres:
        condition: service_healthy


  postgres:
    image: postgres:17-alpine
    restart: always
    environment:
      POSTGRES_DB: MailArchiver
      POSTGRES_USER: mailuser
      POSTGRES_PASSWORD: masterkey
    volumes:
      - ./postgres-data:/var/lib/postgresql/data
    networks:
      - postgres
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U mailuser -d MailArchiver"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 10s

networks:
  postgres:

5.2 Open-Archiver

5.2.1 Запуск докер контейнера через repo git clone
5.2.2 Proxmox-Helper-scripts
5.2.3 Как исправить баг: Open Archiver не сохраняет файлы с кириллицей

5.3 Bichon

5.3.1 Docker run & docker-compose из quick start с официального git repo

docker run
# Pull the image
docker pull rustmailer/bichon:latest

# Create data directory
mkdir -p ./bichon-data

# Run container
docker run -d \
  --name bichon \
  -p 15630:15630 \
  -v $(pwd)/bichon-data:/data \
  -e BICHON_LOG_LEVEL=info \
  -e BICHON_ROOT_DIR=/data \
 -e ICHON_ENCRYPT_PASSWORD="samohosting" \
 -e BICHON_CORS_ORIGINS=http://SERVER_IP:15630 \
  rustmailer/bichon:latest
docker-compose.yml
services:
  bichon:
    container_name: bichon
    ports:
      - 15630:15630
    volumes:
      - ./opt/bichon:/data
    environment:
      - BICHON_LOG_LEVEL=info
      - BICHON_ROOT_DIR=/data
      - BICHON_ENCRYPT_PASSWORD="samohosting"
      - BICHON_CORS_ORIGINS=http://SERVER_IP:15630
    image: rustmailer/bichon:latest
networks: {}

5.4 Piler

5.4.1 Docker-compose из официального git repo

необходимо создать 2 файла для запуска контейнера

piler.cnf
manticore.conf

без них у Вас не проихойдет монтирование(т.к. на хосте отсутствуют данные файлы)
volumes:
- ./manticore.conf:/etc/manticoresearch/manticore.conf
- ./piler.cnf:/etc/mysql/conf.d/piler.cnf:ro

docker-compose.yml

services:
  mysql:
    image: mariadb:12.0.2
    container_name: mysql
    restart: unless-stopped
    cap_drop:
      - ALL
    cap_add:
      - dac_override
      - setuid
      - setgid
    environment:
      - MYSQL_DATABASE=piler
      - MYSQL_USER=piler
      - MYSQL_PASSWORD=piler123
      - MYSQL_RANDOM_ROOT_PASSWORD=yes
    command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    volumes:
      - db_data:/var/lib/mysql
      - ./piler.cnf:/etc/mysql/conf.d/piler.cnf:ro
  manticore:
    image: manticoresearch/manticore:14.1.0
    container_name: manticore
    restart: unless-stopped
    volumes:
      - ./manticore.conf:/etc/manticoresearch/manticore.conf
      - piler_manticore:/var/lib/manticore
    deploy:
      resources:
        reservations:
          memory: 512M
        limits:
          memory: 512M
  piler:
    image: sutoj/piler:${VERSION:-1.4.8}
    container_name: piler
    init: true
    environment:
      - MANTICORE_HOSTNAME=manticore
      - MEMCACHED_HOSTNAME=memcached
      - MYSQL_HOSTNAME=mysql
      - MYSQL_DATABASE=piler
      - MYSQL_USER=piler
      - MYSQL_PASSWORD=piler123
      - PILER_HOSTNAME=${ARCHIVE_HOST:-192.168.1.145:8005}
      - RT=1
    ports:
      - 25:25
      - 05:80
    volumes:
      - piler_etc:/etc/piler
      - piler_store:/var/piler/store
    healthcheck:
      test: curl -s smtp://localhost/
      interval: 20s
      timeout: 3s
      start_period: 15s
      retries: 3
    deploy:
      resources:
        reservations:
          memory: 512M
        limits:
          memory: 512M
    depends_on:
      - mysql
      - memcached
      - manticore
  memcached:
    image: memcached
    container_name: memcached
    command: -m 64
volumes:
  db_data: {}
  piler_etc: {}
  piler_manticore: {}
  piler_store: {}
networks: {}

Смело задавайте Ваши вопросы\комментарии, а так же Ваш опыт эксплутации этих и других сервисов.

1 лайк

Хорошая идея, кстати. А то все же уже в курсе, что …

Вот думаю, что было бы неплохо еще проверить возможность работы с папками почты. Например, импортировать только указанные. Или все, кроме указанных. И можно ли смешивать письма в одноименных папках с разных почтовых серверов.

Было бы неплохо еще иметь потенциальную возможность выгрузки почты обратно в ящик, например, случился чебурнет и доступа gmail нет, но есть домашний архив, вот взял этот архив и выгрузил на условный yandex mail.

так из участников моего тестирования умеет только - Mail-Archiver

#bug

Open Archiver не дает сохранить файлы с кириллицей

В @телеграмме один из самохостят @hageshii666 выявил и починил баг

Как @hageshii666 используя DeepSeek нашел и устранил проблему

Вот линк на то что мне дипсик выплюнул
DeepSeek

Вот тут надо редактировать код
/opt/openarchiver/packages/backend/dist/api/controllers/

Да, поменял в storage.controller.js и всё заработало как надо

Вот это:

            const fileName = path.basename(safePath);
            res.setHeader('Content-Disposition', `attachment; filename="${fileName}"`);
            fileStream.pipe(res);

Заменил на это:

            const fileName = path.basename(safePath);
            // Кодируем имя файла для безопасного использования в HTTP-заголовках
            const encodedFileName = encodeURIComponent(fileName)
                .replace(/['()]/g, escape)
                .replace(/\*/g, '%2A');
            // Устанавливаем два варианта заголовка для совместимости
            const safeFileName = fileName.replace(/[^\x20-\x7E]/g, '_'); // Только ASCII символы
            res.setHeader(
                'Content-Disposition', 
                `attachment; filename="${safeFileName}"; filename*=UTF-8''${encodedFileName}`
            );
            fileStream.pipe(res);

Я же(еще не видя его ответа) - пошел изучать github open-archiver’a и нашел:

  1. Ишью OpenArchiver/issues/182
  2. А внутри ссылку на OpenArchiver/commit
Как решить проблему по примеру issue\commit'а

Где в файле

/opt/openarchiver/packages/backend/dist/api/controllers/storage.controller.js

строчку

res.setHeader('Content-Disposition', `attachment; filename="${fileName}"`);

заменяют на

const encodedFileName = encodeURIComponent(fileName);
res.setHeader('Content-Disposition', `attachment; filename*=UTF-8''${encodedFileName}`);

Что позволяет исправить проблему с кодировкой в названии скаиваемого файла.

Коммит пока в билд текущей сборки не попал, посему правим ручками и живем счастливо.

Еще раз спасибо @hageshii666 за наводку на баг и починку!

1 лайк