Удаление старой почты

Начну пожалуй с того, что благодоря пользователю RockMan я решил данную проблему. Он меня порядком позлил, попинал, но всё таки его слова заставили меня докопаться до сути проблемы. Итак.

Какие нужны параметры, для того чтобы почта удалялась как положенно.

Во-первых,

$ zmprov gs my_server_name | grep -i purge
zimbraMailPurgeBatchSize: 10000  
zimbraMailPurgeSleepInterval: 5m 

Во-вторых,

$ zmprov gc my_COS | grep -i life
zimbraMailMessageLifetime: 31d
zimbraMailSpamLifetime: 1d
zimbraMailTrashLifetime: 1d 

Вот эти 5 параметров необходимых для удаления почты.

Большое внимание нужно уделить параметру.

zimbraMailPurgeSleepInterval: 5m 

В веб морде этот параметр нужно установить в 2 местах.

1. Глобальные настройки.

"Время между последовательными очистками почтового ящика"

2. Сервера.

"Время между последовательными очистками почтового ящика"

 

Этот параметр означает следущее, что через каждые 5 минут будет удаляться почта. Сейчас поясню.

Например у вас есть 10 почтовых ящиков.

Первый ящик у вас будет очищаться в 13.00. Второй ящик у вас будет очищаться 13.05 третий в 13.10 и так далее. То есть за 50 минут у вас очистяться 10 ящиков. Не сложно посчтить за сколько очистяться ваши ящики если их у вас, например 10 000.

!!!При выставлении 1m у меня повис сервак. При выставлении 15 минут (слишком долговато), 5 минут как выяснилось моя комфортная зона!!!

В логах выглядит это следующим образом. (логи хронятся /opt/zimbra/log/mailbox.log )

 
cat /opt/zimbra/log/mailbox.log | grep -i purge
...................
[MailboxPurge] [name=VASIA@MEGODOMEN.RU;mid=482;] purge - Purging messages.
[MailboxPurge] [name=VASIA@MEGODOMEN.RU;mid=482;] mailop - Deleting items: 5348,5349,5350,5351.
...................

Скрипт удалять не буду. Потому что это неплохой кастыль. И пока я разбирался с самой проблемой скрипт трудился как часики. В дальнейшем я его переделаю, чтобы он отрабатывал если ящик заполнился на процентов так 80 или 90 (если например письма с большими вложениями). Но это будет потом, сейчас передомной стоит другая задача.

Дальше пост останется без изменений. Дабы История была интересней :).

### Старый пост ###

Была такая проблема, что Zimbra не удаляла старую почту (сроком 31 день). Почтовики понемногу заполнялись (сложная структура писем, очень много народу проверяют с одного ящика), и по мере заполнения мы их чистили ручками. Приятного мало. Да и не всегда об этом вспоминали. Вот, собственно, тут я и задумался. Крутил-вертел Zimbr'у, в общем, понял, что проще будет написать скрипт самому. Начал шерстить по интернету и наткнулся.

http://www.zimbra.com/forums/administrators/32614-solved-delete-mails-vi...

Cкрипт простой, но опять же не автоматический. А я планирую его завести в crontab и запускать где-нибудь в час ночи.

Не долго думая, я сваял свой. Как всегда, всё пытаюсь подробно комментировать.

#!/bin/bash
 
#Разного рода переменные
 
DOMAIN_NAME="megodomen.ru"     # имя домена почты
EMAIL=/tmp/email.list           # список email адресов, существующих в Zimbra
MESID=/tmp/mesid.list           # список ID сообщений, которые мы хотим удалить
 
##################################### ТЕЛО СКРИПТА #####################################
/opt/zimbra/bin/zmprov -l gaa $DOMAIN_NAME | sort > $EMAIL  # выгружаем почту с Zimbra сортируем и записываем в фаил 

#теперь находим письма, которые были получены 18 дней назад
#именно их мы хотим удалить
#и узнаём их ID
cat $EMAIL
for i in $(cat $EMAIL);
 do
echo "$i"  
  /opt/zimbra/bin/zmmailbox -z -m $i s -l 9999 in:Inbox | grep `date -d '-18 day' +%m/%d/%y`| sed -e "s/^\s\s*//" | sed -e "s/\s\s*/ /g" | cut -d" " -f2 > $MESID
 
##Теперь мы начинаем эти письма удалять. 
  cat $MESID
  for a in $(cat $MESID | grep ^- | sed s/-//g )
  do
  /opt/zimbra/bin/zmmailbox -z -m $i deleteMessage $a
  done
 
  for a in $(cat $MESID | sed /-/d)
  do
  /opt/zimbra/bin/zmmailbox -z -m $i deleteConversation $a
  done
 
RES=$?
if [ "$RES" == "0" ]; then echo "[Ok]"; else echo "[Err]"; fi
done

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

Что делает команда

/opt/zimbra/bin/zmmailbox -z -m $i s -l 9999 in:Inbox 

где:

i - это у нас переменная, а именно название почтового ящика.

-l 9999 - (можно ставить больше) это сколько писем мы должно увидеть. По умолчанию вы увидите только 25.

Теперь пример из головы.

Допустим мы хотим почистить почту пользователя VASIA@megodomen.ru допустим X дней назад.

Для начала мы её найдём.

zmmailbox -z -m VASIA@megodomen.ru s -l 9999 in:Inbox | grep `date -d '-X day' +%m/%d/%y`

И видим (тут я заостряю ваше внимание только на самом главном).

28. -6747  conv   Рекламисты            Инструмен          XM/X/11 15:19
29.  6744  conv   Мария, Анна (2)       Мы ищем            XM/X/11 15:00

Я думаю вы заметили тоже, что ID разные. Есть с -  и есть без него. Вот это, как бы, и есть разница.

Сейчас поясню - это сообщение.

А без - это тоже сообщение, но называется по другому. В Zimbr'е оно называется conversation (что в переводе с англ. "разговор"). Если вы посмотрите через веб-морду, то увидите такое.

И если вы напишете

zmmailbox -z -m VASIA@megodomen.ru deleteMessage 6744

то получите

ERROR: mail.NO_SUCH_MSG (no such message: 6744)

Хотя оно существет.

Правильная команда для удаления этого сообщения будет такая

zmmailbox -z -m VASIA@megodomen.ru deleteConversation 6744 

Но прошу заметить, что если вы напишите

zmmailbox -z -m VASIA@megodomen.ru deleteConversation 6747

а мы помним, что этот ID был  -6747,

то мы получим

ERROR: mail.NO_SUCH_CONV (no such conversation: 6747)

Потому что это сообщение относиться к типу Message. А правильная команда будет такой

zmmailbox -z -m VASIA@megodomen.ru deleteMessage 6747

Поэтому скрипт делится, как бы, на 2 части:

1-ая часть удаляет сообщения типа Message:

for a in $(cat $MESID | grep ^- | sed s/-//g )
do
/opt/zimbra/bin/zmmailbox -z -m $i deleteMessage $a
done

А 2-ая удаляет сообщения типа Conversation:

for a in $(cat $MESID | sed /-/d)
do
/opt/zimbra/bin/zmmailbox -z -m $i deleteConversation $a
done

!!!ВНИМАНИЕ!!!

Я уже писал об этом, но повторюсь. Для приложений надо указывать полный путь. Например,

/opt/zimbra/bin/zmmailbox

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

P.S. Надеюсь кому-нибудь пригодится это, если вдруг он столкнётся с такой же проблемой как я. И, как обычно, оставляйте ваши пожелания и вопросы в комментах. По возможности буду на них отвечать. Желаю удачного дня.

968
Поблагодарили:

Комментарии

Это работает для всей почты во всех папках? Я так понял, что только в inbox, правильно? 

А ты смекалист ;)

Вот кусочек добавь и будет ещё из спама удалять :) (А далше по аналогии)

 

Переменную

JUNKID=/tmp/junkid.list

 

Вот тут дописать строчечку 

for i in $(cat $EMAIL);
 do
echo "$i"
  /opt/zimbra/bin/zmmailbox -z -m $i s -l 9999 in:Inbox | grep `date -d '-35 day' +%m/%d/%y`| sed -e "s/^ss*//" | sed -e "s/ss*/ /g" | cut -d" " -f2 > $MESID
  /opt/zimbra/bin/zmmailbox -z -m $i s -l 9999 in:Junk | grep `date -d '-35 day' +%m/%d/%y`| sed -e "s/^ss*//" | sed -e "s/ss*/ /g" | cut -d" " -f2 > $JUNKID

 

 И (почти) в самый конец

  for a in $(cat $JUNKID | grep ^- | sed s/-//g )
  do
  /opt/zimbra/bin/zmmailbox -z -m $i deleteMessage $a
  done
 
  for a in $(cat $JUNKID | grep /-/d)
  do
  /opt/zimbra/bin/zmmailbox -z -m $i deleteConversation $a
  done

 

Я потом себе тоже это дописал. Я скрипт потом немного переделаю хочу чтобы чистил ящики например если он заполнен на 95%. Но это будет ещё не скоро. Будут вопросы, пишите, постораюсь ответить.

 Осталось понять как сделать так, что бы чистились ящики с любой вложенностью папок и с неизвестными именами. 

 

Ну а кто мешает нам делать так?

zmmailbox -z -m VASIA@megodomen.ru getallfolders

Это командочка выдаст все папки которые есть на почте у VASIA@megodomen.ru.

Например вот так.

$ zmmailbox -z -m VASIA@megodemon.ru getallfolders
        Id  View      Unread   Msg Count  Path
----------  ----  ----------  ----------  ----------
         1  conv           0           0  /
        16  docu           0           0  /Briefcase
        10  appo           0           0  /Calendar
        14  mess           0           0  /Chats
         7  cont           0           0  /Contacts
         6  mess           0           0  /Drafts
        13  cont           0           0  /Emailed Contacts
         2  mess        1027        1030  /Inbox
         4  mess         247         247  /Junk
        12  wiki           0           0  /Notebook
         5  mess           0           0  /Sent
        15  task           0           0  /Tasks
         3  conv           0           0  /Trash
 

Но нам нужны папки, даже те которые создаст пользователь для хранения писем (например). Ну а это строчки со значением mess.

Для удобства можно сделать вот так.

$ zmmailbox -z -m VASIA@megodomen.ru getallfolders | grep -i mess
        14  mess           0           0  /Chats
         6  mess           0           0  /Drafts
         2  mess        1027        1030  /Inbox
         4  mess         247         247  /Junk
         5  mess           0           0  /Sent

Вывод записать в файлик.

Теперь мы знаем какие папки есть у пользователя.

Обрабатываем файлик, удаляем все символы до символа /, потом удалить символ /. И мы получим чистые названия папок.

Записываем их в файлик. и читаем в переменную (например i), а её подставляем в скрипт. И так до тех пор пока не дойдём до конца строки. А потом берём другой почтовый ящик и всё заного. Делов то.

P.S. Придумать алгоритм не долго. Долго его делать и тестировать :) Желаю удачи. Будет здорово если ты поделишься готовым вариантом.
 

Спасибо!!

Решить такую же задачу при помощи скриптов IMAPTOOLS не получилось именно из-за того, что я не знал как получить имя папки. Эта методика позволить расширить задачу -- пропускать папку с именем Archive. 

Чуть попозже начну "пилить" Спасибо за идеи. ;-) 

Всегда пожалуйста :)

в строчке

/opt/zimbra/bin/zmmailbox -z -m $i s -l 9999 in:Inbox | grep `date -d '-18 day' +%m/%d/%y`| sed -e "s/^\s\s*//" | sed -e "s/\s\s*/ /g" | cut -d" " -f2 > $MESID
 

параметр 9999 нужно поменять на 999, аналогично и для $JUNKID

канечно можно просто у нас такие почтовики бывают в которых тыщ так 12 000 :) а так канечно можно и 999 а можно и 20

Это в версии 7.1 ограничение стоит
usage:
  search(s)                    [opts] {query}
  -l/--limit <arg>             max number of results to return (1-1000, default=25)

            Добрый день, господа. Если кому нужно, выложу свой скрипт для удаления старой почты. Передо мной стояла задача удалить почту у всех пользователей до определённой даты из папок "Входящие" и "Отправленные" для уменьшения объёма дискового пространства, занимаемого почтовыми сообщениями. Скрипт сделан на базе уже упоминавшегося автором материала - www.zimbra.com/forums/administrators/32614-solved-delete-mails-via-cli-based-date.html с небольшими изменениями. Ключевое изменение здесь - это необратимое удаление писем с невозможностью их восстановления из "Корзины". Таким образом удаляются файлы почтовый сообщений, что приводит к высвобождению дискового пространства. Предварительно был сделан полный архив всех ящиков пользователей.
Сам скрипт :

#!/bin/bash
#
 
############################################################## ПЕРЕМЕННЫЕ ##############################################################################
 
ZIMBRA_BIN=/opt/zimbra/bin				#Путь к исполняемым файлам
EMAIL=/tmp/email_list					#Список пользователей
sn=1							#Номер строки в списке пользователей (для счётчика)
sall=$(wc -l $EMAIL | awk '{ print $1 }')		#Общее количество строк в списке пользователей (для счётчика)
 
 
 
 
############################################################## СКРИПТ ##################################################################################
#Запрос ввода даты, ДО которой будут удалены сообщения в ящиках пользователей. Формат - месяц/день/год.
 
echo "Enter the time that you would like to delete messages up to, in mm/dd/yy format. Example 04/10/09:"
read THEDATE
  
$ZIMBRA_BIN/zmprov -l gaa ваш_домен | sort > $EMAIL   		 #Выгружаем список пользователей в файл и сортируем
 
while read line 							 #Читаем файл со списком пользователей, пока в нём есть строки
do 
 echo "Processing $line... ($sn/$sall)"                  		 #Отображаем имя пользователя, чей почтовый ящик сейчас обрабатывается и счётчик (текущий/всего)
 touch /tmp/deleteOldMessagesList.txt					 #Создаём временный файл, куда будут записываться id удаляемых сообщений и команды на их удаление
 
#Обрабатываем папку "Входящие"
#Получаем id сообщений
 
for i in `$ZIMBRA_BIN/zmmailbox -z -m $line search -l 1000 "in:/Inbox (before:$THEDATE)" | grep conv | sed -e "s/^ss*//" | sed -e "s/ss*/ /g" | cut -d" " -f2`
do
if [[ $i =~ [-]{1} ]]							#Если перед id есть "-", то это сообщение (Message). Если нет "-", то это разговор (Conversation).
then
MESSAGEID=${i#-}
echo "deleteMessage $MESSAGEID" >> /tmp/deleteOldMessagesList.txt	#Пишем команду на удаление сообщения для этого id во временный файл
else
echo "deleteConversation $i" >> /tmp/deleteOldMessagesList.txt		#Пишем команду на удаление разговора для этого id во временный файл
fi
done
 
#Обрабатываем папку "Отправленные" по аналогии с папкой "Входящие"
 
for i in `$ZIMBRA_BIN/zmmailbox -z -m $line search -l 1000 "in:/Sent (before:$THEDATE)" | grep conv | sed -e "s/^ss*//" | sed -e "s/ss*/ /g" | cut -d" " -f2`
do
if [[ $i =~ [-]{1} ]]
then
MESSAGEID=${i#-}
echo "deleteMessage $MESSAGEID" >> /tmp/deleteOldMessagesList.txt
else
echo "deleteConversation $i" >> /tmp/deleteOldMessagesList.txt
fi
done
 
#Удаляем сообщения
 
$ZIMBRA_BIN/zmmailbox -z -m $line < /tmp/deleteOldMessagesList.txt >> /tmp/process.log 		#Удаляем сообщения по id с помощью команд из временного файла, пишем лог-файл
$ZIMBRA_BIN/zmmailbox -z -m $line emptyDumpster							#Удаляем сообщения без возможности восстановления. В противном случае, файлы сообщений остаются на диске.
rm -f /tmp/deleteOldMessagesList.txt								#Удаляем временный файл с id сообщений и командами на удаление
echo "Messages for $line are successfully deleted!"							#Вывод об успешной очистке почтового ящика
echo												#Вставка пустой строки для разделения
sn=$[sn + 1]     										#Увеличиваем номер строки на единицу (для счётчика)
 
done < $EMAIL
 
 
       Скрипт не претендует на идеально грамотное решение, ибо знаний в программировании пока немного. В частности, грамотнее было бы реализовать получение всех папок у пользователя в ящике с передачей их названий в переменные (как уже советовал автор выше в комментариях), а обработку папок надо было попробовать реализовать в функции. Но он мне помог очистить ящики около 250 пользователей за раз при вводе только одного параметра - даты, до которой сообщения должны быть удалены. Пока только не смог разобраться со счётчиком - если заранее (до выполнения скрипта) не был создан файл /tmp/email_list, то счётчик всех строк в файле не отображается. Если файл уже был, то всё в порядке. Может, кто-нибудь подскажет, в чём проблема? Буду признателен за любую подсказку.
А и не надо чтобы он притендовал. Главное это записать мысль на бумаге. И не забыть куда эту бумагу положил. Я вот сейчас смотрел на свой скрипт и ваще не фига не понял. Даже задался вопросом точно ли я это писал. Насчёт файлика.
А скрипту хватает прав на создание этого файла и его записи? Попробуй в начале скрипти создавать его touche ну а потом в конце просто его удалять.
Для такой проверки для начало просто сделай скрипт по созданию файла и например внесения в него почтовых адресов. Если дело не прокатит. То поиграйся с chmod или chown (вечно путаю эти два слова никак не могу запомнить за что они отвечают). Если не получится то попробуй запустить этот скрипт не из под root а из под zabbix.
Желаю удачи. А за скриптик спасибо. Пусть лежит вдруг пригодится :).
 Я пробовал создавать файлик с самого начала в скрипте, ситуация не меняется. Запускаю из-под zimbra, права на создание и удаление есть. От root'а только не пробовал. Может, это как-то связано с пайпами баша, но я пока только изучаю программирование и не до конца разобрался в вопросе. 
Спасибо за пожелание. Ваш подробный разбор и комментарии мне тоже очень помогли:)
Програмирование это хорошо.
Я вот лично вообще не в зуб ногой в програмировании.
Я бы даже больше сказал я не умею и не знаю как это програмировать... Не прогер я. А написание скрипта методом проб и ошибок. Методом написал заработало @#$сь и забыл (хотя во время обучения в вузе писали мы огромные и интересные проги по фильтрации шумов видео сигнала, писали свои архиваторы, писали на асемблере, програмировали микросхемы и чипы, писали именно машинным кодом типа 0012 09dc, разрабатывали и програмировали свои нейросети, а также учились работать с графикой рисовали всяких снеговиков сабачек, чтобы они маргали глазами или открывали рот, это было реально очень интересно). А сейчас... ну ели ели код чужой почитать могу :) но чтобы прогить неее ну нафиГ. Если канечно цель именно в этом чтобы прям прогить. Тогда это круто. Лично мне не хватает усидчивости и терпения. У меня этот файлик имееет следующие параметры
chmod 755
chown zimbra zimbra
и файлик в mc у меня отображается со *delet_old_message.sh
запускается он у меня вот так (в крон табе именно скрон таб пользователя zimbra чтобы его просмотреть логинимся под пользователем zimbra и пишем команду crontab -l)
*/10 * * * * /home/username/new.sh
запускаю я его из под пользователя zimbra из дериктории где распологается фаил
zimbra@Zimbra:/home/username$ ./delet_old_message.sh
дериктория /tmp имеет следующие параметры
Chmod 41777
Chown root root
P.S. надеюсь это тебе как-то поможет.
P.p.S.s. я тут просмотерл твой файлик ещё разок. Попробуй вместо переменных в коде указывать именно полную директорию. Ну то есть вместо
$ZIMBRA_BIN/zmmailbox
написать вот так

/opt/zimbra/bin/zmmailbox
У меня бывали случаи что скрипт не отрабатывал пока были переменные. Заменил их полными путями. И всё Стало ОГОНЬ.
Бред канечно...  но рассказал всё что делал и знал :)

А как почистить папки, вложенные в Inbox с русскоязычными именами ?

Попытка получить папки так
zmmailbox -z -m MBOX@megadomen.ru getallfolders | grep mess | sed -e "s/^ss*//" | sed -e "s/ss*/ /g" | cut -d" " -f5 | grep Inbox
и циклом перебрать закончилась ошибкой
ERROR: mail.NO_SUCH_FOLDER (no such folder path: /Inbox/XXXX)
Проблема решена так: 
export LC_ALL='ru_RU.UTF-8'
Подскажите, как можно отобрать письма по размеру? По размеру именно писем, а не ящиков? 
К сожалению не могу подсказать.
Может быть есть вывод команды что находится в папке и там будут поля с размером писем.
Как вариант.
На данный момент не имею возможности даже проверить свою теорию
Подскажите как составить правильно команду для ввода в консоль, что бы можно было очистить папку входящие на определенном ящике, т.е. удалить все письма лежащие во входящих за все время? Можно удаление всех имеющихся писем в этом почтоящике без возвратно минуя папку корзина.