Как настроить один экземпляр почтового ящика imaplib для нескольких потоков? - PullRequest
0 голосов
/ 17 мая 2019

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

class User():
    services = {'company1': 'STOPED',
                'company2': 'STOPED'}

    def __init__(self, user_settings):
        self.user_name = user_settings['User']
        self.user_settings = user_settings

        self.global_mailbox = None

    def company1(self):
        service_name = 'company1'
        settings = self.user_settings['Company1']
        gb_mail = False

        def mailbox_check(mailbox):
            nonlocal settings, service_name

            mailbox.noop()
            status, mails = mailbox.search(None, '(UNSEEN)', '(FROM "company1@cmp.com")')

            ....

        if not settings['Mail Login']:
            if self.global_mailbox:
                mailbox = self.global_mailbox
                gb_mail = True
            else:
                self.SET_GLOBAL_MAIL()
                if not self.global_mailbox:
                    return
                else:
                    mailbox = self.global_mailbox
        else:
            mail_host = 'imap.{0}'.format(settings['Mail Login'].split('@')[-1])
            mail_login = settings['Mail Login']
            mail_password = settings['Mail Password']

            mailbox = imaplib.IMAP4_SSL(mail_host)
            mailbox.sock.settimeout(43200)

            mailbox.login(mail_login, mail_password)
            mailbox.select('INBOX')
            gb_mail = False

         while self.services[service_name] != 'STOPED':
             time.sleep(5)
             new_orders = self.mailbox_check(mailbox)
             if new_orders:
                 action()    
             if self.services[service_name] == 'STOPED':
                 break

    def company2(self):
        service_name = 'company2'
        settings = self.user_settings['Company2']
        gb_mail = False

        def mailbox_check(mailbox):
            nonlocal settings, service_name

            mailbox.noop()
            status, mails = mailbox.search(None, '(UNSEEN)', '(FROM "company2@cmp.com")')

            ....

        if not settings['Mail Login']:
            if self.global_mailbox:
                mailbox = self.global_mailbox
                gb_mail = True
            else:
                self.SET_GLOBAL_MAIL()
                if not self.global_mailbox:
                    return
                else:
                    mailbox = self.global_mailbox
        else:
            mail_host = 'imap.{0}'.format(settings['Mail Login'].split('@')[-1])
            mail_login = settings['Mail Login']
            mail_password = settings['Mail Password']

            mailbox = imaplib.IMAP4_SSL(mail_host)
            mailbox.sock.settimeout(43200)

            mailbox.login(mail_login, mail_password)
            mailbox.select('INBOX')
            gb_mail = False

         while self.services[service_name] != 'STOPED':
             time.sleep(5)
             new_orders = self.mailbox_check(mailbox)
             if new_orders:
                 action()    
             if self.services[service_name] == 'STOPED':
                 break

def SET_GLOBAL_MAIL(self)
    try:
        gb_mail = self.user_settings['Global Mail']
        mail_host = 'imap.{0}'.format(gb_mail['Login'].split('@')[-1])
        mail_login = gb_mail['Login']
        mail_password = gb_mail['Password']
        mailbox = imaplib.IMAP4_SSL(mail_host)
        mailbox.sock.settimeout(43200)
        mailbox.login(mail_login, mail_password)
        mailbox.select('INBOX')
        self.global_mailbox = mailbox
    except:
        self.global_mailbox = None
        pass

def START_ALL(self):
    self.SET_GLOBAL_MAIL()
    for service in self.services.keys():
        self.services[service] = 'RUNNING'
        threading.Thread(target=lambda: self.__getattribute__(service)(), name='{0} [{1} service thread]'.format(self.user_name, service), daemon=True).start()

>>>user = User(settings)
>>>user.START_ALL()

Через несколько секунд я получил эти ошибки:

imaplib.IMAP4.abort: команда: SEARCH => ошибка сокета:EOF

imaplib.IMAP4.abort: ошибка сокета: EOF

imaplib.IMAP4.abort: команда: NOOP => ошибка сокета: EOF

imaplib.IMAP4.abort:ошибка сокета: [WinError 10014] Система обнаружила недопустимый адрес указателя при попытке использовать аргумент указателя в вызове

ssl.SSLError: [SSL: SSLV3_ALERT_BAD_RECORD_MAC] предупреждение о плохой записи sslv3 mac (_ssl.c: 2273)

Если для каждого потока я создаю новый сеанс imap, все работает нормально, но GMAIL имеет ограничение на одновременное подключение через imap.И пользователь может иметь более 15 компаний для разбора.Как настроить один глобальный почтовый ящик для пользователя на все его действия?

1 Ответ

1 голос
/ 17 мая 2019

Не имеет смысла использовать одно и то же соединение IMAP для нескольких разговоров, поскольку существует одно соединение с одним сокетом и один контекст на стороне сервера. Если один поток запрашивает mailbox1, а второй - mailbox2, сервер последовательно выберет 2 почтовых ящика и останется в последнем.

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

...