Как получить UIDNEXT в скрипте канала python procmail?

У меня есть этот скрипт Python для вставки необработанной электронной почты в БД. Не спрашивайте меня, почему я вставляю необработанную почту в базу данных.

import sys
from DB import *
import email

full_msg = sys.stdin.readlines()
j =  ''.join(full_msg)
msg = email.message_from_string(j)

sql = '''INSERT INTO Email(Id, Message) VALUES (NULL, %s)'''
db = DB()
db.query(sql, (msg, ))

Было бы здорово, если бы я мог получить uid этого сообщения, поэтому, если я, например, удалю сообщение из базы данных, я также могу удалить сообщение со своим uid на сервере imap.

Я не хочу входить на сервер imap, а затем удалять сообщение по uid, потому что я не знаю пароль пользователя, так как он зашифрован.

Я думал получить, например, msg['Message-Id'], а затем выполнить поиск файлов в почтовом каталоге пользователя для этого Message-Id и удалить фактический файл, но для меня это звучит совершенно неправильно.

Я знаю, что в python у вас есть что-то вроде UIDNEXT в imaplib, но это при условии, что я вошел в систему, а я нет.

ОБНОВИТЬ:

С этим я могу получить следующий uid, но мне нужно войти в систему. Как получить UIDNEXT без входа в систему? Кстати, я использую postfix/dovecot с mysql.

import getpass, sys
from imapclient import IMAPClient

try:
    hostname, username = sys.argv[1:]
except ValueError:
    print 'usage %s hostname username' % sys.argv[0]

c = IMAPClient(hostname, ssl=True)

try:
    c.login(username, getpass.getpass())
except c.Error, e:
    print "Could not login in:", e
    sys.exit(1)

else:
    select_dict = c.select_folder('INBOX', readonly=True)
    for k, v in select_dict.items():
        if k == 'UIDNEXT':
            print '%s: %r' % (k,v)
    c.logout()

НОВОЕ ОБНОВЛЕНИЕ

Образец dovecot-uidlist

16762 W105493 S104093 :1417408077.2609_1.zumance
16763 S18340 W18608 :1417429204.3464_1.zumance

Код для получения последней строки uid dovecot-uidlist:

l = open("dovecot-uidlist").readlines()
print l[-1].split(" ")[0]

Это завершенный скрипт для почтового канала:

import sys
import email
import re
from DB import *
full_msg = sys.stdin.readlines()
j =  ''.join(full_msg)

msg = email.message_from_string(j)
match = re.search(r'[\w\.-]+@[\w\.-]+', msg['to'])

address = match.group(0)
address = address.split("@")

with open("/var/vmail/"+address[1]+"/"+address[0]+"/dovecot-uidlist", 'r') as f:
  first_line = f.readline()
  nextuid = first_line.split(" ")
  nextuid = re.findall(r'\d+', nextuid[2])

sql = '''INSERT INTO Email(Id, Message, Uid, Domain, Mbox) VALUES (NULL, %s, %s, %s, %s)'''
db = DB()
db.query(sql, (msg, nextuid[0], address[1], address[0],  ))

Сообщение в блоге с файлами по адресу https://pregmatch.org/read/python-procmail


person pregmatch    schedule 01.12.2014    source источник
comment
@Oldskool, спасибо, что заметили это. Но это не просто вопрос о питоне, это глобальный вопрос, касающийся постфикса, голубятни и т. д.   -  person pregmatch    schedule 01.12.2014


Ответы (2)


Dovecot поддерживает сопоставление между UID и именем файла в файле dovecot-uidlist. Файл содержит сначала строку заголовка, а затем по одной строке на сообщение.

Строка заголовка выглядит так:

1 1173189136 20221

Первая цифра — это версия, вторая — IMAP UIDVALIDITY, а последняя — следующий UID, который будет использоваться.

После этого каждое сообщение имеет свою собственную строку, выглядящую так:

20220 1035478339.27041_118.example.org:2,S

Первое слово — это UID, следующее — имя файла.

Дополнительную информацию можно найти на вики dovecot.

person Jenny D    schedule 01.12.2014
comment
Спасибо, Дженни Д., это была полезная информация. Пожалуйста, если вы посмотрите мое НОВОЕ ОБНОВЛЕНИЕ, вы увидите, что у меня там есть кое-что лишнее (3, 4, 5 столбцов подряд). Что ты предлагаешь мне сделать? Доставить почту, а затем прочитать последнюю строку домена/пользователя/dovecot-uidlist, разделенную и взять первый столбец в последней строке? - person pregmatch; 01.12.2014
comment
Это звучит вероятно. Попробуйте и посмотрите, что получится? - person Jenny D; 01.12.2014
comment
Это решение работает. Я пытался выполнить предварительную аутентификацию с помощью python на dovecot, но это не сработало. Ваше решение сработало. Спасибо. - person pregmatch; 01.12.2014
comment
У меня проблемы с голубятней. dovecot-uidlist обновляется новым адресом электронной почты (uid, имя файла) только тогда, когда почтовый клиент проверяет наличие новых писем. Только после этого электронная почта перемещается из new/ в cur/ и обновляется файл dovecot-uidlist. При этом последняя строка dovecot-uidlist не содержит соответствующего uid. Решит ли это +1 к последнему сообщению uid, как вы думаете? - person pregmatch; 01.12.2014
comment
Посмотрите на строку заголовка. Как я уже писал, последнее слово в строке заголовка — это следующий UID, который будет использоваться. - person Jenny D; 01.12.2014
comment
Глупо с моей стороны. Спасибо. - person pregmatch; 01.12.2014
comment
У меня снова проблемы. dovecot-uidlist обновляется только при проверке новой электронной почты. Это означает, что когда я передаю, например, 10 электронных писем, все они будут иметь одинаковый uid, поскольку ни одно из них не перемещается из new/ в cur/. Есть ли способ исправить это? - person pregmatch; 03.12.2014
comment
Я нашел maildir_empty_new = yes (было нет), но это ничего не делает. Может быть, мне нужно снять галочку с чего-то еще, чтобы эта штука заработала. Вы знакомы с этим? - person pregmatch; 03.12.2014
comment
взгляните на мое решение. - person pregmatch; 04.12.2014
comment
Я рад, что вы нашли решение, даже если оно не соответствовало требованию, что оно должно работать без входа в систему. - person Jenny D; 04.12.2014
comment
(Я искал решение без входа в систему/пароля, так как я не знаю пароль). В любом случае ваше предложение поставило меня на правильный путь. - person pregmatch; 04.12.2014

Поскольку синтаксический анализ dovecot-uidlist не будет работать, потому что список не будет обновляться, пока вы не проверите электронную почту с помощью своего почтового клиента, я решил пойти с другим решением. Это решение представляет собой механизм предварительной аутентификации dovecot. В моем скрипте procmail на python я решил сделать что-то вроде этого:

import subprocess
p = subprocess.Popen( "/usr/libexec/dovecot/imap -u "+user, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
p.stdin.write("b select INBOX\n")
p.stdin.write("e logout\n")
(stdoutdata, stderrdata) = p.communicate()
print stdoutdata

print stderrdata

stdoutdata дает мне вывод, который выглядит так:

* PREAUTH [CAPABILITY IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE IDLE SORT SORT=DISPLAY THREAD=REFERENCES THREAD=REFS THREAD=ORDEREDSUBJECT MULTIAPPEND URL-PARTIAL CATENATE UNSELECT CHILDREN NAMESPACE UIDPLUS LIST-EXTENDED I18NLEVEL=1 CONDSTORE QRESYNC ESEARCH ESORT SEARCHRES WITHIN CONTEXT=SEARCH LIST-STATUS SPECIAL-USE BINARY MOVE] Logged in as [email protected]
* FLAGS (\Answered \Flagged \Deleted \Seen \Draft $NotJunk NotJunk $Forwarded)
* OK [PERMANENTFLAGS (\Answered \Flagged \Deleted \Seen \Draft $NotJunk NotJunk $Forwarded \*)] Flags permitted.
* 5574 EXISTS
* 0 RECENT
* OK [UIDVALIDITY 1412448500] UIDs valid
* OK [UIDNEXT 16875] Predicted next UID
* OK [HIGHESTMODSEQ 3051] Highest
b OK [READ-WRITE] Select completed (0.009 secs).
* BYE Logging out
e OK Logout completed.

Теперь все, что мне нужно сделать, это проанализировать эту часть этого вывода:

* OK [UIDVALIDITY 1412448500] UIDs valid
* OK [UIDNEXT 16875] Predicted next UID

Эта предварительная аутентификация решила мою проблему. Я опубликую полное решение с частью анализа позже сегодня (и в своем блоге).

РЕШЕНИЕ:

import subprocess
pSub = subprocess.Popen( "/usr/libexec/dovecot/imap -u "+username+"@"+domain_parsed, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
pSub.stdin.write("b select INBOX\n")
pSub.stdin.write("e logout\n")
(stdoutdata, stderrdata) = pSub.communicate()
dovecotStream = open("/var/www/domain.com/scripts/server/dovecot","w")
dovecotStream.write(stdoutdata)
dovecotStream.close()


nextuidNo = []
with open("/var/www/domain.com/scripts/server/dovecot") as dovecotFile:
    dovecotFilelines = dovecotFile.read()
for dovecotFileline in dovecotFilelines.split('\n'):
    matchCheck = re.findall(r'\[UIDNEXT.+\]', dovecotFileline)
        if len(matchCheck):
            nextuidNo = re.findall(r'\d+', matchCheck[0])

print nextuidNo #this is list

Полная запись в блоге по адресу: https://pregmatch.org/read/dovecot-preauth-python

person pregmatch    schedule 04.12.2014