скрипт для переноса электронной почты из одного ящика в другой

Скрипт максимально простой, написан на php, так же потребуется модуль php-imap, работает из командной строки любого устройства (сервера). Принцип простой, скрипт подключается к исходному ящику по протоколу IMAP сканирует структуру почтовых папок, подключается к целевому ящику IMAP, воссоздаёт папки которых нет и загружает в них письма. Опционально может создать структуру папок локально и скачать в них письма в формате eml.

<?php

//папка, куда будет сохраняться структура ящика с письмами
$path_to_mail = 'boxes';

//сохранять локально копию ящика
$save_local_copy = 0;

//декодировать имя папки или нет для локальной копии
$decode_folder_name = 1;

//данные ящика откуда переезжаем (например яндекс)
$source_server = 'imap.yandex.ru';
$source_port = '993';
$source_user = '{user}@{domain}.ru';
$source_pass = 'P@$$word';

//данные ящика куда переезжаем
$target_server = 'mail.{domain}.ru';
$target_port = '993';
$target_user = '{user}@{domain}.ru';
$target_pass = 'P@$$word';

function check_folder_exist($folders_list, $check_folder_name) {
  $fl_exist = false;
  foreach ($folders_list as $val) {
    if ($val->name == $check_folder_name) {
      $fl_exist = true;
    }
  }
  return $fl_exist;
}

$path_to_mail .= DIRECTORY_SEPARATOR.$source_user.DIRECTORY_SEPARATOR;

$source_server_str = "{".$source_server.":".$source_port."/imap/ssl}";
$source_mbox = imap_open($source_server_str,$source_user,$source_pass)
      or die("can't connect: " . imap_last_error());

$target_server_str = "{".$target_server.":".$target_port."/imap/ssl}";
$target_mbox = imap_open($target_server_str,$target_user,$target_pass)
      or die("can't connect: " . imap_last_error());

$target_list = imap_getmailboxes($target_mbox, $target_server_str, "*");
if (is_array($target_list)) {
    foreach ($target_list as $key => $val) {
      $folder_name = str_replace($target_server_str,'',$val->name);
      $target_delimiter = $val->delimiter;
    }
} else {
    echo "imap_getmailboxes failed: ".imap_last_error()."\n";
}

$source_list = imap_getmailboxes($source_mbox, $source_server_str, "*");
if (is_array($source_list)) {
    foreach ($source_list as $key => $val) {
        $source_full_folder_name = $val->name;
        $source_delimiter = $val->delimiter;
        $con=imap_open($source_full_folder_name, $source_user, $source_pass);
        $number_msg=imap_num_msg($con);
        $folder_name = str_replace($source_server_str,'',$source_full_folder_name);
        if ($decode_folder_name) {
          $current_folder_name = mb_convert_encoding($folder_name, "UTF8", "UTF7-IMAP");
        } else {
          $current_folder_name = $folder_name;
        }
        $full_new_folder_name = $target_server_str.str_replace($source_delimiter,$target_delimiter,$folder_name);
        echo $full_new_folder_name."\n";
        if (!(check_folder_exist($target_list, $full_new_folder_name))) {
          echo 'папка "'.mb_convert_encoding($folder_name, "UTF8", "UTF7-IMAP").'" отсутствует на сервере, создаём'."\n";
          
          imap_createmailbox($target_mbox, $full_new_folder_name);
        }
        if ((!file_exists($path_to_mail.str_replace($source_delimiter,DIRECTORY_SEPARATOR,$current_folder_name))) and ($save_local_copy)) {
            mkdir($path_to_mail.str_replace($source_delimiter,DIRECTORY_SEPARATOR,$current_folder_name), 0777, true);
        }
        echo mb_convert_encoding($folder_name, "UTF8", "UTF7-IMAP").": ";
        echo $number_msg."\n";
        for ($i = 1; $i <= $number_msg; $i++) {
          if (!imap_ping($con)) {
              // если вдруг связь первалась, восстанавливаем
              echo "$i ой, reconnect $source_server\n";
              $i--;
              $con=imap_open($val->name, $source_user, $source_pass);
          }
          if (!imap_ping($target_mbox)) {
              // если вдруг связь первалась, восстанавливаем
              echo "$i ой, reconnect $target_server\n";
              $target_mbox = imap_open($target_server_str,$target_user,$target_pass);
          }
          echo ".";
          $headers = imap_fetchheader($con, $i, FT_PREFETCHTEXT);
          $body = imap_body($con, $i);
          imap_append($target_mbox, $full_new_folder_name, $headers."\n\n".$body,"\\Seen");
          if ($save_local_copy) {
            file_put_contents($path_to_mail.str_replace($val->delimiter,DIRECTORY_SEPARATOR,$current_folder_name).DIRECTORY_SEPARATOR.str_pad($i, 8, "0", STR_PAD_LEFT).".eml", $headers."\n\n".$body);
          }
        }
        echo "\n";
      imap_close($con);
    }
} else {
    echo "imap_getmailboxes failed: ".imap_last_error()."\n";
}
imap_close($source_mbox);
imap_close($target_mbox);

?>

$path_to_mail — относительный путь к папке, где будет храниться локальная копия ящика, актуально когда «$save_local_copy = 1»

$save_local_copy = 1 будет сохраняться локальная копия писем на жёстком диске, соответственно, если «0» — не будет

$decode_folder_name = 1 имена папок будут декодированы в нормальный вид, если «0» — то будет использован формат UTF7, как они хранятся на сервере.

Все письма, которые будут перенесены в новый ящик получат статус прочитанных, извините, я не заморачивался с перенесением флагов.

Перед прочтением сообщения пингуется соединение с сервером IMAP, в случае его обрыва — соединение восстанавливается. Замедление совсем небольшое, зато надёжность вырастает многократно.

Учитываются разделители вложенности папок (например у яндекса это «|», в iRedMail «/»).

Копирование писем допускается один раз, если вы прервёте процесс и запустите снова, часть сообщений задублируется.

Отправить
Поделиться