May-04-2021, 09:58 AM
Hello my dears,
i can't find the error in my Python script. I use the Scricpt to pick up messages from my old email address. Actually everything works. I just get an error message at the end. So what do I want to achieve?
An LDAp user created under uid = stefan.example, ou = users, dc = example, dc = com has the following ObjectClass and attributes:
i can't find the error in my Python script. I use the Scricpt to pick up messages from my old email address. Actually everything works. I just get an error message at the end. So what do I want to achieve?
An LDAp user created under uid = stefan.example, ou = users, dc = example, dc = com has the following ObjectClass and attributes:
root@dsme01:~# ldapsearch -xZZ -b "ou=users,dc=harnet,dc=de" uid=stefan.exemple # extended LDIF # # LDAPv3 # base <ou=users,dc=example,dc=com> with scope subtree # filter: uid=stefan.exemple # requesting: ALL # # stefan.exemple, users, example.com dn: uid=stefan.exemple,ou=users,dc=exemple,dc=com facsimileTelephoneNumber: ########### gidNumber: 10000 homePhone: ########### homePostalAddress: ... loginShell: /bin/bash mailEnabled: TRUE mailQuota: 100M uid: stefan.exemple cn: Stefan exemple givenName: Stefan homeDirectory: /home/stefan.exemple initials: STH mobile: ########### sn: exemple telephoneNumber: ############ uidNumber: 10000 userPassword:: ... title: admin postalAddress: ... birthDate: yyyy-mm-dd fileAs: Stefan exemple dcMailMessageStore: /vmail/mailboxes/example.com/stefan.exemple/mail objectClass: evolutionPerson objectClass: top objectClass: person objectClass: organizationalPerson objectClass: inetOrgPerson objectClass: mailExtension objectClass: posixAccount objectClass: dcMailUser mail: [email protected]and the associated subtree
# [email protected], stefan.example, users, exemple.com dn: [email protected],uid=stefan.example,ou=users,dc=example,dc=com dcAccountStatus: active dcSubMailAddress: [email protected] objectClass: dcExternalMailAccount objectClass: top objectClass: dcPosixSubAccount dcPosixOwnerURL: ldap:///uid=stefan.exemple,ou=users,dc=exemple,dc=com?uid,uidNu mber,gidNumber,dcMailMessageStore?base?(&(objectClass=posixAccount)(objectClass=dcMailUser)) gidNumber: 10000 uid: stefan.example uidNumber: 10000 dcMailMessageStore: /vmail/mailboxes/exemple.com/stefan.exemple/mailThe Python script getmail-ldap-py (attached as an attachment) also includes the following conf file
root@dsme01:~# cat /home/secmail/getmail-ldap.cfg [Main] # Path to getmail GetmailBinary=/usr/bin/getmail # Directory that should be used as a storage by getmail GetmailDir=/home/secmail/getmail_data # Read default values for getmail from this file DefaultGetmailConfigFile=/home/secmail/getmailrc_template.cfg # Save the final configuration files which include the LDAP details to this directory ConfigFileOutputDir=/home/secmail/getmail_config [Logging] verbose = 2 # Write messages to the following log file LogFile=/var/log/getmail-ldap.log # If a severe error occures a mail goes to the admin # SMTP-Server to use for sending this error notification MailServer=dsme01.intern.exempla.com # Mail address of the sender of this error notification [email protected] # Recipients of this error notification # separate multiple recipients by comma [email protected] # Subject of the error notification MailSubject=Getmail-LDAP Error [LDAP] # Read LDAP information from this server LDAPServer=ldaps://ldap.intern.example.com # Authenticate with the following DN BindDN=uid=secmail, ou=users, dc=example, dc=com # Authenticate with the following password BindPassword=####### # Restrict search of external mail accounts to this DN SearchDN=ou=users, dc=example, dc=com # Scope of search for external mail accounts # Possible values include SUB, ONE and BASE SearchScope=SUB # Identify external mail accounts with the following filter SearchFilter=(&(dcSubMailAddress=*)(objectClass=dcExternalMailAccount)(dcAccountStatus=active)(dcRetrieveType=*)(dcRetrieveLogin=*)(dcRetrievePassword=*)) # List of LDAP-Attributes used to determine the following variables # 1. Name for resulting getmail configuration file (must be unique) # 2. Type for mail collection e.g. BrokenUIDLPOP3Retriever # 3. Mail server to collect mails from # 4. Login for mail server # 5. Password for mail server # 6. UID for User # separate by comma RelevantAttributes=dcSubMailAddress,dcRetrieveType,dcRetrieveServer,dcRetrieveLogin,dcRetrievePassword,uidIf I start the getmail-ldap-py script, I always get the following error message.
Error:secmail@dsme01:~$ ./getmail-ldap.py
Traceback (most recent call last):
File "/usr/lib/python2.7/logging/handlers.py", line 958, in emit
smtp.sendmail(self.fromaddr, self.toaddrs, msg)
File "/usr/lib/python2.7/smtplib.py", line 737, in sendmail
raise SMTPSenderRefused(code, resp, from_addr)
SMTPSenderRefused: (530, '5.7.0 Must issue a STARTTLS command first', '[email protected]')
Logged from file getmail-ldap.py, line 179
Sorry that I am posting the Python script in the code block. I didn't know how to attach the code as a file attachment.secmail@dsme01:~$ cat getmail-ldap.py #!/usr/bin/python # File: getmail-ldap.py try: import errno import string import logging import logging.handlers import ldap import ConfigParser import ldif import threading from StringIO import StringIO from ldap.cidict import cidict from os.path import os from subprocess import Popen,PIPE except ImportError: print """Cannot find all required libraries please install them and try again""" raise SystemExit config_file_location = '/home/secmail/getmail-ldap.cfg' def pid_exists(pid): """Is there a process with PID pid?""" if pid < 0: return False exist = False try: os.kill(pid, 0) exist = 1 except OSError, x: if x.errno != errno.ESRCH: raise return exist def get_search_results(results): """Given a set of results, return a list of LDAPSearchResult objects. """ res = [] if type(results) == tuple and len(results) == 2 : (code, arr) = results elif type(results) == list: arr = results if len(results) == 0: return res for item in arr: res.append( LDAPSearchResult(item) ) return res class LDAPSearchResult: """A class to model LDAP results. """ dn = '' def __init__(self, entry_tuple): """Create a new LDAPSearchResult object.""" (dn, attrs) = entry_tuple if dn: self.dn = dn else: return self.attrs = cidict(attrs) def get_attributes(self): """Get a dictionary of all attributes. get_attributes()->{'name1':['value1','value2',...], 'name2: [value1...]} """ return self.attrs def set_attributes(self, attr_dict): """Set the list of attributes for this record. The format of the dictionary should be string key, list of string alues. e.g. {'cn': ['M Butcher','Matt Butcher']} set_attributes(attr_dictionary) """ self.attrs = cidict(attr_dict) def has_attribute(self, attr_name): """Returns true if there is an attribute by this name in the record. has_attribute(string attr_name)->boolean """ return self.attrs.has_key( attr_name ) def get_attr_values(self, key): """Get a list of attribute values. get_attr_values(string key)->['value1','value2'] """ return self.attrs[key] def get_attr_names(self): """Get a list of attribute names. get_attr_names()->['name1','name2',...] """ return self.attrs.keys() def get_dn(self): """Get the DN string for the record. get_dn()->string dn """ return self.dn def pretty_print(self): """Create a nice string representation of this object. pretty_print()->string """ str = "DN: " + self.dn + "\n" for a, v_list in self.attrs.iteritems(): str = str + "Name: " + a + "\n" for v in v_list: str = str + " Value: " + v + "\n" str = str + "========" return str def to_ldif(self): """Get an LDIF representation of this record. to_ldif()->string """ out = StringIO() ldif_out = ldif.LDIFWriter(out) ldif_out.unparse(self.dn, self.attrs) return out.getvalue() class RetrieveMails(threading.Thread): def __init__(self, getmail_binary, config_filename, config_data_dir): threading.Thread.__init__(self) self.getmail_binary, self.config_filename, self.config_data_dir = \ getmail_binary, config_filename, config_data_dir def run(self): try: command = [self.getmail_binary, \ #'--quiet', \ '--rcfile=' + self.config_filename, \ '--getmaildir=' + self.config_data_dir] self.pid_filename = self.config_filename + '.pid' # Check for a pidfile to see if the daemon already runs try: pid_file = file(self.pid_filename,'r') pid_number = pid = int(pid_file.read().strip()) pid_file.close() except IOError: pid = None # Check whether process is really running if pid: pid = pid_exists(pid) if not pid: getmail_process = Popen(command, shell=False,stdout=PIPE,stderr=PIPE) try: file(self.pid_filename,'w+').write("%s\n" % getmail_process.pid) getmail_process.wait() finally: os.remove(self.pid_filename) # Zur Sicherheit die erstellte Konfigurationsdatei loeschen (Login-Daten!) os.remove(self.config_filename) stderr_output=string.join(getmail_process.stderr.readlines()) if getmail_process.returncode <> 0 or len(stderr_output.strip())>0 : raise Exception, "Getmail command failed for " + " ".join(command) \ +"\nStdErr: \n" + string.join(stderr_output.strip()) \ +"\nStdOut: \n" + string.join(getmail_process.stdout.readlines()) else: log_object.info("Command " + " ".join(command) +\ " not executed, existing pid " + str(pid_number) + " found") except: log_object.exception("An error occured!") class RetrieveAccount: account_name = None account_type = None login = None password = None uid = None server = None def __init__(self, account_name=None, account_type=None, server=None, login=None, password=None, uid=None): self.account_name, self.account_type, self.login, self.password, self.uid, self.server = \ account_name, account_type, login, password, uid, server class GetmailConfigFile(ConfigParser.SafeConfigParser): output_filename = None def __init__(self, defaults, default_config_filename=None, output_filename=None): ConfigParser.SafeConfigParser.__init__(self, defaults) if default_config_filename is not None: self.read(default_config_filename) self.output_filename = output_filename def set_pop3_account(self, newRetrieveAccount): self.set('retriever','server',newRetrieveAccount.server) self.set('retriever','type',newRetrieveAccount.account_type) self.set('retriever','username',newRetrieveAccount.login) self.set('retriever','password',newRetrieveAccount.password) self.set('retriever','uid',newRetrieveAccount.uid) self.set('destination','arguments','("-i", "'+newRetrieveAccount.uid+'@example.com",)') def write(self): if self.output_filename is not None: """try: output_file = open(self.output_filename, 'wb') except: raise Exception, "Unable to open " + \ self.output_filename + "for writing" finally: output_file.close() """ os.umask(0077) output_file = open(self.output_filename, 'wb') ConfigParser.SafeConfigParser.write(self, output_file) else: raise Exception, "No output file for configuration defined" # Konfigurationsdatei lesen config_object = ConfigParser.SafeConfigParser() config_object.read(config_file_location) # Set-up Logging log_object = logging.getLogger("getmail-ldap") log_object.setLevel(logging.DEBUG) # This handler writes everything to a log file. log_file_handler = logging.FileHandler(config_object.get('Logging','LogFile')) log_file_formatter = logging.Formatter("%(levelname)s %(asctime)s %(funcName)s %(lineno)d %(message)s") log_file_handler.setFormatter(log_file_formatter) log_file_handler.setLevel(logging.DEBUG) log_object.addHandler(log_file_handler) # This handler emails anything that is an error or worse. log_smtp_handler = logging.handlers.SMTPHandler(\ config_object.get('Logging','MailServer'),\ config_object.get('Logging','MailFrom'),\ config_object.get('Logging','MailTo').split(','),\ config_object.get('Logging','MailSubject')) log_smtp_handler.setLevel(logging.ERROR) log_smtp_handler.setFormatter(log_file_formatter) log_object.addHandler(log_smtp_handler) def main_call(): ## first you must open a connection to the LDAP server ldap_object = ldap.initialize(config_object.get('LDAP','LDAPServer')) ldap_object.simple_bind_s(\ config_object.get('LDAP','BindDN'),\ config_object.get('LDAP','BindPassword')) # searching doesn't require a bind in LDAP V3. # If you're using LDAP v2, set the next line appropriately # and do a bind as shown in the above example. # you can also set this to ldap.VERSION2 if you're using a v2 directory # you should set the next option to ldap.VERSION2 if you're using a v2 directory ldap_object.protocol_version = ldap.VERSION3 ## The next lines will also need to be changed to support your search requirements and directory ## retrieve all attributes - again adjust to your needs - see documentation for more options if config_object.get('LDAP','SearchScope').upper() == "SUB": search_scope = ldap.SCOPE_SUBTREE elif config_object.get('LDAP','SearchScope').upper() == "ONE": search_scope = ldap.SCOPE_ONELEVEL else: search_scope = ldap.SCOPE_BASE ldap_result_id = ldap_object.search( \ config_object.get('LDAP','SearchDN'), \ search_scope, config_object.get('LDAP','SearchFilter'), \ None) ldap_results = [] while 1: result_type, result_data = ldap_object.result(ldap_result_id, 0) if (result_data == []): break else: ## here you don't have to append to a list ## you could do whatever you want with the individual entry ## The appending to list is just for illustration. if result_type == ldap.RES_SEARCH_ENTRY: ldap_results += get_search_results(result_data) for ldap_result in ldap_results: account = RetrieveAccount( \ # Account Name \ ldap_result.get_attr_values(\ config_object.get('LDAP','RelevantAttributes').split(',')[0])[0] ,\ # Account Type \ ldap_result.get_attr_values(\ config_object.get('LDAP','RelevantAttributes').split(',')[1])[0],\ # Server \ ldap_result.get_attr_values(\ config_object.get('LDAP','RelevantAttributes').split(',')[2])[0],\ # Login \ ldap_result.get_attr_values(\ config_object.get('LDAP','RelevantAttributes').split(',')[3])[0],\ # Password \ ldap_result.get_attr_values(\ config_object.get('LDAP','RelevantAttributes').split(',')[4])[0],\ # UID \ ldap_result.get_attr_values(\ config_object.get('LDAP','RelevantAttributes').split(',')[5])[0],\ ) config_output_filename = os.path.join(\ config_object.get('Main','ConfigFileOutputDir'), \ "getmail_" + \ account.account_name + \ ".cfg") config_file = GetmailConfigFile(None, \ config_object.get('Main','DefaultGetmailConfigFile'), config_output_filename) config_file.set_pop3_account(account) log_object.info("Writing Account Configuration for " + account.account_name + \ " to file " + config_output_filename) config_file.write() RetrieveMails(\ config_object.get('Main','GetmailBinary'), \ config_output_filename, \ config_object.get('Main','GetmailDir')\ ).start() #print config_output_filename #print "Name " + account.account_name #print "Type " + account.account_type #print "Server " + account.server #print "Login " + account.login #print "Password " + account.password #print "UID" + account.uid #print "-----------------" #print ldap_result.pretty_print() if __name__ == "__main__": try: main_call(); except: log_object.exception("An error occured!")Do you find the mistake? Kind regards from Stefan Harbich