Google, куда ты дел моё место в GMail? А вы точно знаете, как в GMail работают ярлыки?

в 14:57, , рубрики: gmail api, Go, golang, Google, Google API, mongodb

Google, куда ты дел моё место в GMail? А вы точно знаете, как в GMail работают ярлыки? - 1
Стал я замечать, что из 15 гигабайт бесплатного месте, предоставленного Google, у меня почта занимает уже почти 12 гигабайт. И такая тенденция меня не радует.
С другой стороны я в качестве почтового клиента использую Thunderbird с полной синхронизацией. Т.е. все письма должны быть закачены. Так вот папка Thunderbird со всеми письмами и индексами занимает всего 3 гигабайта. Хотя по логике вещей размер должен не просто более менее совпадать с занятым местом на GMail, а быть побольше, т.к. Thunderbird не архивирует письма, а хранит как есть и еще индексы строит для ускорения поиска.
Проблема на лицо! Начинаем докапываться до сути.

Начал я того, что зашёл в ярлык (да, в случае с GMail правильно говорить именно ярлык, а не папка, подробности тут) «Вся почта» и увидел, что у меня чуть больше 500 тысяч сообщений. Ситуация усложнялась тем, что у меня порядка 100 ярлыков! А ярлыки в GMail — это типичные папки в Thunderbird. Как быстро посчитать общее количество писем в Thunderbird я не нашел. Но забегая вперед скажу, что в нем у меня их порядка 200 тысяч. Отсюда становится понятно, почему на диске место занимается меньше.
Но остается все равно все тот же вопрос: что это за такие 300 тысяч сообщений в GMail, которые не видны в Thunderbird, но занимают место на GMail?

Пытливость ума + желание не поспать ночью + желание пощупать Go на реальной задаче привели меня к решению, что нужно взять компилятор Go, изучить GMail API и посмотреть, что же там под капотом у GMail.

Совсем коротко о впечатлениях о Go
Только самый ленивый не писал про обработку ошибок в Go. Только на них я и обратил внимание более пристально.
В остальном:

  • Начал писать на следующий вечер
  • Еще один язык
  • Жизнь заставит — буду писать и на Go
  • Для меня и C/C++, Python, Java (и PHP тоже) — тоже себе языки для своих ниш
  • Наверное я просто всеядный

Да и статья не про Go.

Как я выше отметил, у меня порядка сотни ярлыков. Письма обычно имеют один ярлык. И мне захотелось выяснить, сколько писем у меня помечены каждым ярлыком и сколько они суммарно занимают места.
Я не нашел способа узнать в web-интерфейсе GMail размеры ярлыков (объём писем, помеченных тем или иным ярлыком).
Засучил рукава, установил компилятор Go, поднял в Docker контейнере MongoDB (Да, я такой вот извращенец! Но это мой pet project и что хочу, то и использую, особенно в учебных целях) и стал говнокодить творить.
Дальше я буду ссылаться на вот этот мой проект.
Забираю все свои метки с GMail и складываю их в базу Users.labels: list:

GMailMessagesSize -importLabels -mongoConnectionString 10.211.55.5
Imported labels: 112

Забираю ID всех сообщений, которые имеются в ящике Users.messages: list:

GMailMessagesSize -mongoConnectionString 10.211.55.5 -importMessages
Processed 100 messages
Processed 200 messages
Processed 300 messages
.......
Processed 523100 messages
Processed 523115 messages

Забирается конечно не быстро, но как тут распараллелиться я не нашел (API не позволяет).
Пока у нас есть только список ID сообщений, а нам нужно про каждое сообщение знать его ярлыки и размер. Для этого есть метод Users.messages: get. Но отрабатывает он не быстро, даже не смотря на то, что в запросе я указываю какие именно поля меня интересуют (internalDate, labelIds, sizeEstimate).
Реализацию Batching Requests я что-то не нашел.
Но я же пишу на Go и грех не использовать горутины! Сказано — сделано. Тянем информацию в количество потоков (сколько захотим, но я поставил ограничение в 50). Если интернет быстрый и комп не тупит, то начинаем быстро упираться в лимит рейта запросов от Google. Скрипт можно остановить и продолжить, а можно просто упорно ждать, т.к. при срабатывании лимита горутины спят по 5 секунд и потом продолжают мучить Google. Да, можно было бы каждый раз увеличивать время сна, например, в два раза и не забыть про ограничение сверху. Но в этом случае простые 5 секунд вполне себе решение.
Я свои 500 тысяч писем обработал суммарно, кажется, примерно за 3 часа. В общем время вменяемое.

GMailMessagesSize -mongoConnectionString 10.211.55.5 -processMessages -procNum 20
............................Procecced 100 messages
............................Procecced 200 messages
............................Procecced 300 messages
....
............................Processed 523100 messages
............................Processed 523115 messages

Там не только точки выскакивали. Если упереться в лимит, то вместо точки S (sleep) или может быть сообщение уже было удалено, то NF (NotFound).
В результате всех перечисленных выше страданий в MongoDB имеется коллекция ярлыков и коллекция сообщений:

{ 
    "SizeEstimate" : NumberLong(63422), 
    "_id" : ObjectId("5677188d2afd90a80e5e06f2"), 
    "id" : "136b83b1ff739dec", 
    "internaldate" : ISODate("2012-04-15T22:47:51.000+0000"), 
    "labelids" : [
        "CATEGORY_PROMOTIONS"
    ], 
    "processed" : true
}

Теперь под рукой есть все данные, чтобы начать их анализировать.
Сначала я решил экспортировать в CSV информацию по ярлыкам, количеству сообщений и их суммарный размер.

GMailMessagesSize -mongoConnectionString 10.211.55.5 -showSizes
LabelId;Label name;Messages size;Messages count
Label_11;Archives;21279;4
Label_12;Archives/2012;18684;3
CATEGORY_FORUMS;CATEGORY_FORUMS;519396295;30038
CATEGORY_PERSONAL;CATEGORY_PERSONAL;5040188875;268116
CATEGORY_PROMOTIONS;CATEGORY_PROMOTIONS;2990655727;36508
CATEGORY_SOCIAL;CATEGORY_SOCIAL;205976374;6553
CATEGORY_UPDATES;CATEGORY_UPDATES;2769764066;180729
CHAT;CHAT;0;0
DRAFT;DRAFT;82817;6
IMPORTANT;IMPORTANT;6600492209;159268
INBOX;INBOX;40306538;334
UNREAD;UNREAD;479586429;11678
.....
Label_97;INBOX/Coursera;6021524;151
Label_77;INBOX/Временная;1077571;28
Label_63;INBOX/Ответить!!!;6195999;12
Label_67;INBOX/Поездка в США;1693366;11

Это CSV, который мне было удобно открыть в Excel и поизучать (посортировать и фильтровать).
Google, куда ты дел моё место в GMail? А вы точно знаете, как в GMail работают ярлыки? - 2
И вот на этом этапе я серьезно задумался. Что такое 6 гигов каких-то важных ( с ярлыком IMPORTANT ) сообщений? Что такое 11678 непрочитанных сообщений (с ярлыком UNREAD)? У меня (как я думал) все сообщения прочитаны! Даже если в строке поиска GMail ввести label:unread, то он выводит всего 106 непрочитанных сообщений! Что происходит?

Гугление данной ситуации привело к форумам, где другие задавались вопросом — почему удаленные в Thunderbird сообщения не удаляются в GMail? Ну там много разных случаев. Я вам расскажу о самом, на мой взгляд, печальном.

На этом месте те, кто пользуется GMail'ом исключительно в браузере могут пожалеть, что начали читать эту статью. НО!!! Вы возможно читаете почту в том числе с мобильного. И возможно у вас там не родной клиент GMail. В таком случае, возможно у вас такая же проблема, как и у меня!

Не буду дальше томить и расскажу, что же все таки происходит.
Следите за руками. Последовательность событий такая:

  1. Приходит письмо в GMail
  2. Письму назначается ярлыки INBOX, UNREAD и (вот тут важно) возможно еще какой-нибудь дополнительный ярлык, например CATEGORY_PROMOTIONS
  3. В почтовом клиенте вы открыли письмо. Ярлык UNREAD снялся.
  4. В почтовом клиенте вы удалили письмо
  5. Барабанная дробь: ярлык INBOX снялся. И… все, больше ничего
  6. У сообщения остался ярлык CATEGORY_PROMOTIONS

Сообщения с ярлыком CATEGORY_PROMOTIONS отображаются, если в поиске набрать: category:promotions Часто вы так делаете?
Если уж совсем коротко, то письма просто не удаляются! Я их удаляю, а они остаются на GMail.
Тут самое время вспомнить про архивацию писем. И похоже, что это тот самый случай!
Когда в Thunderbird удаление настроено через «Пометить на удаление», потом «Сжатие»:
Google, куда ты дел моё место в GMail? А вы точно знаете, как в GMail работают ярлыки? - 3
И то, что стоит галка помещать в корзину:
Google, куда ты дел моё место в GMail? А вы точно знаете, как в GMail работают ярлыки? - 4
То происходит ВСЕ РАВНО архивация!
Итого: письма уходят в архив. А архив с точки зрения GMail — это письма, которые не имеют видимых ярлыков и не побывали в корзине.
С одной стороны — ничего страшного. Зато письма всегда можно будет найти через поиск.
А что если я не хочу так? Что мне теперь делать?
Как найти и удалить все сообщения из архива? Вот тут неплохой ответ. Но я что-то не рискнул вот так вот удалять все и сразу.
Кстати, в строке поиска я так и не нашел способа показать сообщения, которые имеют только один конкретный ярлык. Т.е. например, я решил удалить все сообщения, которые имеют ярлык CATEGORY_PROMOTIONS и никакой другой. Эти рекламные письма в архиве мне точно не нужны. Кстати, а сколько их там?

GMailMessagesSize -mongoConnectionString 10.211.55.5 -showSizes -l CATEGORY_PROMOTIONS -onlyThisLabel
LabelId;Label name;Messages size;Messages count
CATEGORY_PROMOTIONS;CATEGORY_PROMOTIONS;1197364170;14618

У меня их там на гигабайт накопилось.
-onlyThisLabel важная опция, которая как раз и позволяет найти только те сообщения, которые имеют этот единственный ярлык.

GMailMessagesSize -mongoConnectionString 10.211.55.5 -showSizes -l CATEGORY_PROMOTIONS -l IMPORTANT -onlyThisLabel
LabelId;Label name;Messages size;Messages count
CATEGORY_PROMOTIONS;CATEGORY_PROMOTIONS;1197364170;14618

Да у меня еще на полтора гигабайта «важных рекламных» сообщений :) Обратите внимание, что это в дополнение к просто гигабайту неважной рекламы.
Руки сразу зачесались все это удалить!

GMailMessagesSize -mongoConnectionString 10.211.55.5 -deleteMessages -l CATEGORY_PROMOTIONS -l IMPORTANT -onlyThisLabel -procNum 10

На самом деле письма не удаляются, а помещаются в корзину. Там они через 30 дней либо удалятся совсем, либо можно пойти и вручную почистить самому.

ИТОГО: Если вы удаляете сообщения не через Web-интерфейс GMail, а через сторонний клиент (возможно мобильный), то есть вероятность, что сообщения у вас не удаляются, а архивируются. Для некоторых это даже хорошо. А у кого-то это приводит к тому, что ящик просто неприлично распухает.
И дело даже не в 2 баксах в месяц. Можно и 100 гигов скушать и дальше больше. Хотелось именно разобраться в сути вопроса.

ВНИМАНИЕ!!! Проект писался лично для себя. Это моя первая программа на Go. За сохранность ваших писем я не отвечаю! Но если не пользоваться опцией -deleteMessages, то ничего с вашим ящиком не случится.

Что сделать, чтобы приложение заработало?

  • Use this wizard to create or select a project in the Google Developers Console and automatically turn on the API. Click Continue, then Go to credentials.
  • At the top of the page, select the OAuth consent screen tab. Select an Email address, enter a Product name if not already set, and click the Save button.
  • Select the Credentials tab, click the Add credentials button and select OAuth 2.0 client ID.
  • Select the application type Other, enter the name «Gmail API Quickstart», and click the Create button.
  • Click OK to dismiss the resulting dialog.
  • Click the (Download JSON) button to the right of the client ID.
  • Move this file to your working directory and rename it client_secret.json.

Автор: Labutin

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js