0

How can i set one mailbox parser for user in few different threads ? Each user have 2 or more companies which mails he should parse. In my expample i'm always had errors.

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()

After few seconds i got these errors:

imaplib.IMAP4.abort: command: SEARCH => socket error: EOF

imaplib.IMAP4.abort: socket error: EOF

imaplib.IMAP4.abort: command: NOOP => socket error: EOF

imaplib.IMAP4.abort: socket error: [WinError 10014] The system detected an invalid pointer address in attempting to use a pointer argument in a call

ssl.SSLError: [SSL: SSLV3_ALERT_BAD_RECORD_MAC] sslv3 alert bad record mac (_ssl.c:2273)

If for each thread i'm creating a new imap session all works fine, but GMAIL has a limit for simultaneous connection through imap. And user may have more than 15 companies for parsing. How to setup one global mail for user for all his actions ?

Acamori
  • 327
  • 1
  • 5
  • 15

1 Answers1

1

It does not make really sense to use the same IMAP connection for several conversations because there is one single socket connection and one single server side context. If one thread asks mailbox1 and a second asks for mailbox2, the server will select successively the 2 mailboxes and will stay in last one.

Not speaking of race conditions if two threads simultaneously read from same socket: each will only get quasi random partial data while the other part will be read by the other thread. I am sorry but this is not possible.

Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252