Kategorien

Druckansicht des Beitrags Druckansicht des Beitrags

Dovecot, Exim, OpenLDAP und getmail unter Ubuntu – (4) getmail

Nachdem wir in den drei ersten Teilen zunächst OpenLDAP, Dovecot und Exim eingerichtet haben, geht es nun daran, getmail so einzurichten, dass Mails von einem externen Server via POP3 oder IMAP abgerufen werden und dann dem entsprechenden lokalen Benutzer zugestellt werden. Obwohl fast alles im Blog detailliert beschrieben ist, empfehle ich, die Konfigurationsdateien für das Mailsystem herunterzuladen.

Installation

Wir installieren getmail und das benötigte python-Modul durch den Befehl

sudo apt-get install getmail4 python-ldap

Konfiguration zum Mailabruf von externen Servern

Der Benutzer secmail wird für uns alle Mails abholen und an den jeweiligen Nutzer zustellen. Für diesen Zweck habe ich das Python-Skript getmail-ldap.py geschrieben. Es liest zunächst die Login-Daten aller externen Mail-Accounts aus dem LDAP-Verzeichnis und erzeugt für jeden Mailaccount eine entsprechende Konfigurationsdatei zur Verwendung mit getmail. Anschließend ruft es getmail auf und benachrichtigt im Falle einer Fehlermeldung den Administrator per E-Mail. Die folgenden Schritte führen wir unter dem Benutzer secmail durch, damit die Dateien mit der entsprechenden Berechtigung erzeugt werden. Dazu rufen wir sudo auf:

sudo -u secmail -s

Den folgenden Inhalt

#!/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
	server = None
	def __init__(self, account_name=None, account_type=None, server=None, login=None, password=None):
		self.account_name, self.account_type, self.login, self.password, self.server = \
			account_name, account_type, login, password, 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('destination','arguments','("'+newRetrieveAccount.account_name+'",)')
	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.open(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]\
		)
		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 "-----------------"
		#print ldap_result.pretty_print()

if __name__ == "__main__":
	try:
		main_call();
	except:
		log_object.exception("An error occured!")

speichern wir als /home/secmail/getmail-ldap.py und machen die Datei durch ein

chmod 750 getmail-ldap.py

ausführbar. Das Skript besitzt eine Konfigurationsdatei unter /home/secmail/getmail-ldap.cfg mit dem Inhalt

[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]
# 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=localhost
# Mail address of the sender of this error notification
MailFrom=secmail@myserver
# Recipients of this error notification
# separate multiple recipients by comma
MailTo=root@myserver
# Subject of the error notification
MailSubject=Getmail-LDAP Error

[LDAP]
# Read LDAP information from this server
LDAPServer=myserver
# Authenticate with the following DN
BindDN=uid=secmail, ou=users, o=effinger
# Authenticate with the following password
BindPassword=mysecmailpassword
# Restrict search of external mail accounts to this DN
SearchDN=ou=users, o=effinger
# 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
# separate by comma
RelevantAttributes=dcSubMailAddress,dcRetrieveType,dcRetrieveServer,dcRetrieveLogin,dcRetrievePassword

Die Konfigurationsoptionen habe ich durch Kommentare dokumentiert. In jedem Fall muss in dieser Datei im Abschnitt [LDAP] der LDAPServer von myserver auf den jeweiligen DNS-Eintrag des OpenLDAP-Servers angepasst werden. Auch die Zeile mit BindPassword müssen wir ändern, so dass sie das secmail Passwort enthält. Da diese Datei mit dem Passwort sensible Informationen enthält, die es einem Angreifer erlauben würden, aus dem LDAP-Verzeichnis alle Login-Informationen der externen Mail-Accounts zu lesen, setzen wir die Berechtigung für die Datei so, dass nur secmail darauf zugreifen kann:

chmod 640 getmail-ldap.cfg

Anschließend erzeugen wir die referenzierte Datei /home/secmail/getmailrc_template.cfg mit dem Inhalt

[retriever]
type =
server =
username =
password = 

[destination]
type = MDA_external
path = /usr/sbin/exim4
arguments = ("user@mailhost.tld",)

[options]
# for testing do not delete mails
#delete = false
delete = true
message_log = /var/log/getmail.log
read_all = true
# do not manipulate the header
delivered_to = false
received = false

Die einzelnen Konfigurationsoptionen werden in der Dokumentation von getmail detailliert erläutert. Wichtig ist hier zu wissen, dass das Python-Skript diese Datei als Vorlage nimmt und dann in der Sektion [retriever] die Werte für type, server, username und password aus dem LDAP-Verzeichnis einträgt. In der Sektion [destination] wird der Wert arguments so abgeändert, dass die Mail an den lokalen Benutzer geht. Das Zusammenspiel von getmail und exim wird in einem Forumsbeitrag näher erläutert.
Empfehlung: Zu Beginn ist es sicherlich sinnvoll, im Abschnitt [options] den Wert von delete auf false zu setzen. So werden die Mails vom externen Server zwar heruntergeladen, aber nicht gelöscht. Wenn alles einwandfrei funktioniert, kann man hier den Wert wieder auf true setzen.
Auch hier setzen wir die Berechtigungen für die Datei entsprechend:

chmod 640 getmailrc_template.cfg

Nun erzeugen wir noch ein Verzeichnis, welches getmail benötigt und eines zum Ablegen der finalen Konfigurationsdateien mit den Berechtigungen, so dass nur secmail darauf zugreifen kann.

mkdir -m 750 /home/secmail/getmail_data /home/secmail/getmail_config

Dann erzeugen wir die Logdateien im Verzeichnis /var/log und setzen die Berechtigung so, dass auch secmail in diese Dateien schreiben kann.

sudo touch /var/log/getmail{-ldap,}.log
sudo chown root.secmail /var/log/getmail{-ldap,}.log
sudo chmod 660 /var/log/getmail{-ldap,}.log

Testen des Mailabrufs

Mit dem Aufruf des Pythonskripts durch ein

sudo -u secmail -s
/home/secmail/getmail-ldap.py

und das anschließende Inspizieren der Log-Dateien /var/log/getmail-ldap.log und /var/log/getmail.log können wir testen, ob die Mails heruntergeladen werden. Ob die Zustellung an den lokalen Benutzer geklappt hat, sieht man an neuen Dateien im jeweiligen maildir (hier: /home/paul/mail/paulpanzer@gmx.de/maildir/INBOX/new) bzw. durch Abruf der Mails mit einem Client z.B. per IMAP.

Regelmäßiges Zustellen externer Mails

Damit die Mails regelmäßig von dem externen Server abgerufen werden, richten wir einen Cron-Job ein, der alle fünf Minuten prüft, ob neue Mails vorhanden sind. Dazu führen wir als secmail User

crontab -e

aus und tragen dort die Zeile

*/5 * * * * /home/secmail/getmail-ldap.py

ein. Bei Adam Kane kann man nachlesen, was ein Cron-Job ist.

Feintuning – Logdateien mit Logrotate verwalten

Nachdem nun alles soweit eingerichtet ist, kümmern wir uns noch darum, dass die Logdateien ordentlich aufgeräumt werden. Wir erzeugen deshalb im Verzeichnis /etc/logrotate.d/ die Datei dovecot mit dem Inhalt

# Logrotate Konfiguration für dovecot
/var/log/dovecot.log {
        daily
        missingok
        rotate 14
        compress
        delaycompress
        notifempty
        create 600 root root
}
/var/log/dovecot-deliver.log {
        daily
        missingok
        rotate 14
        compress
        delaycompress
        notifempty
        create 600 root secmail
}

und ebenso die Datei getmail mit diesem Inhalt

# Logrotate Konfiguration für getmail und getmail-ldap
# siehe /home/secmail/getmail-ldap.py
/var/log/getmail.log {
        daily
        missingok
        rotate 14
        compress
        delaycompress
        notifempty
        create 660 root secmail
}
/var/log/getmail-ldap.log {
        daily
        missingok
        rotate 14
        compress
        delaycompress
        notifempty
        create 660 root secmail
}

Wir korrigieren außerdem noch einen kleinen Bug im exim-Paket, indem wir die Zeile

        create 640 Debian-exim adm

in den beiden Dateien exim-base und exim-paniclog im selben Verzeichnis durch folgende Zeile ersetzen

        create 640 Debian-exim root

Tip zum Logging des OpenLDAP-Servers von der OpenLDAP-Mailingliste: Standardmäßig wird alles in die syslog geschrieben. Wenn man der Übersichtlichkeit halber eine eigene Logdatei für OpenLDAP haben möchte, muss man OpenLDAP mitteilen, dass es beim Loggen einen eigenen Selektor (hier:local4) verwenden soll. Dazu muss die Datei /etc/default/slapd die folgende Zeile enthalten:

SLAPD_OPTIONS="-l local4"

Nun konfigurieren wir syslog so, dass es alle Informationen mit diesem Selektor in eine eigene Datei schreibt. Bei Verwendung von sysklogd ergänzen wir in der Datei /etc/syslog.conf folgende Zeile

# Log openldap to separate file
local4.*			-/var/log/slapd.log

Bei Verwendung von rsyslog erzeugen wir die Datei /etc/rsyslog.d/40-slapd.conf mit folgendem Inhalt

# Log openldap to separate file
local4.*			-/var/log/slapd.log
& ~

Außerdem legen wir eine entsprechende Datei namens /etc/logrotate.d/slapd mit dem folgenden Inhalt an.

/var/log/slapd.log {
        daily
        missingok
        rotate 14
        compress
        delaycompress
        notifempty
        create 660 root openldap
}

Damit die Änderungen Wirkung zeigen, müssen wir anfangs eine Logdatei erzeugen und anschließend Syslog und OpenLDAP neu starten bzw. die Konfiguration neu laden.

sudo touch /var/log/slapd.log
sudo chown root.openldap /var/log/slapd.log
sudo chmod 660 /var/log/slapd.log
sudo /etc/init.d/sysklogd reload
sudo /etc/init.d/slapd restart

Links zum getmail-ldap Python-Skript

Bei der Erstellung des Python-Skripts waren einige Webseiten sehr hilfreich, die deshalb hier aufgeführt werden, obowhl sie für die Einrichtung des Mailservers ohne Bedeutung sind.

Weitere Konfigurationsschritte

Die Schritte zur Einrichtung der im ersten Teil angesprochenen Komponenten Roundcube als Webmaildienst, LDAP zur Verwaltung von Addressen und Spamassassin zum Filtern von Spam-Mails sowie eine Anleitung zum Einrichten eins Mail-Clients werden aufgrund von Zeitmangel leider erst in einigen Wochen verfügbar sein.

25 comments to Dovecot, Exim, OpenLDAP und getmail unter Ubuntu – (4) getmail

  • Sehr gutes und ausführliches Tutorial. Danke dafür. 🙂

  • Bernd

    Danke für diese ausführliche Anleitung. Bin schon gespannt auf Teil 5 mit den Komponenten Roundcube und Spamassassin 🙂

  • Michael

    Leider warte ich schon länger auf Teil 5…. 🙁

    Ein sehr gutes Tutorial, welches unbedingt fortgesetzt werden müsste.

    • Teil 5 wird aller Voraussicht nach erst im November folgen, da ich bis Ende Oktober in Singapur bin und mein Ubuntu-Server in Deutschland solange down ist. Eigentlich wollte ich mir in Singapur einen neuen Rechner als Server zusammenstellen, aber da das teurer ist als in Deutschland übers Internet zu bestellen habe ich davon wieder Abstand genommen. Sorry für die Wartezeit!

  • Soeben habe ich mein System auf Karmic Koala aktualisiert mit der Folge, dass mein Python-Skript immer eine Fehler-Mail zustellte mit der Fehlermeldung

    /usr/share/getmail4/getmailcore/baseclasses.py:26: DeprecationWarning: the sets module is deprecated
      import sets

    Der Bug ist bekannt, allerdings scheint sich niemand diesem anzunehmen. Mittlerweile ist aber in dem PPA Repository von Matthias Rosenkranz eine fehlerfreie Version vorhanden. Mit einem

    sudo add-apt-repository ppa:rose
    sudo apt-get update
    sudo apt-get install getmail4

    kann man diese installieren. Bei mir funktioniert sie einwandfrei.

  • […] Dovecot, Exim, OpenLDAP und getmail unter Ubuntu – (4) getmail    Dovecot, Exim, OpenLDAP und getmail unter Ubuntu – (2) Dovecot […]

  • Philipp

    Hallo Markus,
    vielen Dank für das Tutorial, wirklich sehr hilfreich.
    Allerdings funktioniert bei mir das Versenden an remote hosts nicht, wobei ich mir nicht wirklich sicher bin ob das so überhaupt vorgesehen ist. Nach deinem Schema liefert exim ja entweder über den dovecot LDA, einen relay smtp oder eben „direct delivery via smtp“.
    Das funktioniert bei mir allerdings nicht, wenn ich eine email an einen remote host senden will erfolgt eine Abfrage im ldap, natürlich ohne Ergebnis, dann wird der Vorgang beendet: „Unrouteable address“.
    Soweit ich in /etc/exim4/conf.d/router/ sehen konnte, ist auch kein handling vorgesehen. Oder hab ich was überlesen?
    Wie funktioniert bei dir der Versand von mails?

    ich hatte auch noch ein paar kleinere Probleme mit dem Abrufen von mails mit getmail. auch bei gmx, vorallem das initiale downloaden von ca 4k mails:
    Ich verwende SimplePOP3SSLRetriever, was mir erlaubt in getmailrc_template.cfg
    read_all = false
    delete = false
    zu setzen – sonst werden jedes mal alle mails abgerufen. Außerdem bleibt getmail bei mir nach ca 1.6k mails hängen, wenn ich das python script verwende, ein manueller Aufruf des gleichen commandos hingegen funktioniert, warum auch immer. Die logs geben leider auch nichts aufschlussreiches her, aber die Option
    max_messages_per_session = 512
    schafft Abhilfe.

    • Hallo Philipp,

      das Versenden von E-Mails wird je nach Account unterschiedlich gehandhabt:
      1) Versenden von einem lokalen Mail-Account (user@localhost)
      Der Versand klappt nur, wenn der Empfänger auch auf dem lokalen Mailserver ist (z.B. user2@localhost) oder aber für die Empfängeraddresse Mails von einem externen Account abgerufen werden. Der Versand an alle anderen Adressen klappt nicht. Beispiel: Du rufst die E-Mailaddresse user2@gmx.de ab und folglich kann user@localhost auch an user2@gmx.de Mails senden. Dabei laufen die Mails nicht über den GMX-Mailserver sondern werden direkt lokal zugestellt. Dagegen kann der lokale Benutzer keine Mails an beliebig@somedomain.net senden.
      2) Versenden von externen Accounts (im Beispiel zuvor user2@gmx.de)
      Zunächst werden die Mails falls möglich lokal zugestellt (also entweder an eine lokale Mailadresse oder eine, für die Mails abgerufen werden). Ist das nicht möglich, dann wird im LDAP-Verzeichnis der SMTP-Login und der SMTP-Server ausgelesen und die Mail via authentifiziertem SMTP versendet. Beispiel: user2@gmx.de schickt eine Mail an user@localhost, user2@gmx.de und beliebig@somedomain.net. Für die beiden ersten Adressen erfolgt die Zustellung lokal. Bei der letzten Adresse authentifiziert sich Exim als user2@gmx.de bei mail.gmx.net (dem GMX SMTP-Server) und schickt die Mail über diesen ab.

      Die Konfiguration die hier vorgestellt wurde, dient mehr als Heimserver, der eigentlich keine Mails selbst handeln muss. Mittlerweile habe ich auch einen VServer am Laufen und handle die Mails an meine Domain selbst, daher musste ich meine Exim-Konfiguration etwas verändert. Bei Gelegenheit werde ich die neue Konfiguration mal hochladen.

      Zu deinen Anmerkungen mit getmail:
      Ich selbst habe noch keine Probleme festgestellt, wobei ich auch keine derartig großen Mengen an Mails abrufen musste. Für GMX nutze ich bislang den BrokenUIDLPOP3SSLRetriever. Evt. hängt es auch damit zusammen.

      Viele Grüße und weiterhin viel Spaß mit exim und getmail

      Markus

      • Noch'n Philipp

        Hallo Markus,

        zunächst einmal ein riesen Dankeschön für die Veröffentlichung deiner Kenntnisse. Ich hatte bereits einen Dovecot Server mit Getmail, Postfix und ssmtp am laufen, jedoch find ich deine Lösung mit ldap und exim um einiges eleganter. Also nochmals danke. Ich habe jedoch ebenfalls seit 2 Wochen einen vServer am laufen und würde gerne meine Konfiguration auf diesen Übertragen. Zusätzlich soll natürlich auch die eigene Domain damit verwaltet werden. Wäre also auch brennend an deiner erweiterten Exim Config interessiert und hoffe, das sich deine „Gelegenheit“ sehr bald findet 😉

        Viele Grüße,
        Philipp

  • Noch'n Philipp

    Hallo Markus,

    entweder bin ich blind oder du bist doch noch nicht dazu gekommen 🙁 Naja, ich gedulde mich einfach weiter und hoffe, das es irgendwann so weit ist 😉

    • Hat leider etwas länger gedauert, aber hier nun meine letzte exim.conf. Im Gegensatz zu der ursprünglich vorgestellten Konfiguration wird nun im LDAP-Directory auch bei lokalen Mailadressen immer die Domain mitangegeben. Außerdem sind einige kleine Veränderungen im Routing hinzugekommen sowie Spamprüfungen mit SPF.

  • Felix

    Hi,
    ich hab versucht deine Anleitung an mein System anzupassen. Das Auslesen der Accounts (bisher ein Testaccount) aus dem LDAP scheint zu klappen. Ich bekomme allerdings einen Fehler in der getmail-ldap.conf

    INFO 2010-06-28 09:35:23,713 main_call 314 Writing Account Configuration for fetchtest@host-consultants.de to file /home/secmail/getmail_config/getmail_fetchtest@host-consultants.de.cfg
    ERROR 2010-06-28 09:35:23,952 run 179 An error occured!
    Traceback (most recent call last):
    File „./getmail-ldap.py“, line 174, in run
    +“\nStdOut: \n“ + string.join(getmail_process.stdout.readlines())
    Exception: Getmail command failed for /usr/bin/getmail –rcfile=/home/secmail/getmail_config/getmail_fetchtest@host-consultants.de.cfg –getmaildir=/home/secmail/getmail_data
    StdErr:

    StdOut:

    Leider bin ich in Phyton noch nicht so bewandert, hat jemand eine Ahnung woran es liegen könte?

    Gruß Felix

  • Frank

    Hi Markus.

    Schöne Anleitung. An sich genau das, was ich suchte. NUR: ich kriege ums verrecken den Exim nicht dazu eine externe Post auszuliefern.
    Ich versuche von dem externen Test-Account (frank@franksaccount@web.de) auf eine andere externe Adresse zu senden. Alles was ich bekomme ist:

    2011-01-04 13:52:07 H=franks.rechners.home [192.168.199.206] F= rejected RCPT : Unrouteable address

    Lokale Post klappt (sowohl an frank@franks.rechners.home als auch an franksaccount.web.de).
    Gibt es Ansätze, wo ich zu suchen anfangen sollte?

    Gruß Frank.

  • Frank

    Problem erkannt: exim darf auf dem ldap nicht dcSMTP* nicht lesen. Also liegts am slapd und nicht am exim. Nur verstehe ich das jetzt wiederum auch nicht…

  • Gerald

    Bis vor kurzem funktionierte alles perfekt, Vielen Dank dafür.
    Nach einem Update musste ich feststellen das der Mail Abruf nicht mehr funktionierte, da das Modul ldap.open… nicht mehr vorhanden ist.
    Nach Änderung der Zeile von:
    ldap_object = ldap.open(config_object.get(‚LDAP‘,’LDAPServer‘))
    nsch
    ldap_object = ldap.initialize(config_object.get(‚LDAP‘,’LDAPServer‘))

    und Anpassung der URI in Template Datei funktioniert wieder alles.

    Falls einer dasselbe Problem hat.

  • Stefan Harbich

    Hi Markus,

    tolle Anleitung echt super. Mein LDAP Server lauscht auf Port 636. Also verschlüsselt. Da muss ich wohl was an der „getmail-ldap.py anpassen, oder?

    Kannst Du mir da einen Tipp geben wo ich nachschauen muss? Das wäre lieb von Dir. Vorab herzlichen Dank.

    Gruß von Stefan

  • Stefan Harbich

    Hi Markus,

    mit dem Hinweis von Gerald hat es funktioniert. Super, Danke Gerald. Allerdings nutze ich nicht exim4 für das senden der Nachrichten sondern sendmail. Hier meine „getmailrc_template.cfg“
    . . .
    [destination]
    type = MDA_external
    ## path = /usr/sbin/exim4
    path = /usr/sbin/sendmail
    ## arguments = („user@mailhost.tld“,)
    arguments = („-i“,“ich@example.com“)

    [options]
    # for testing do not delete mails
    delete = false
    ## delete = true
    message_log = /var/log/getmail.log
    read_all = true
    # do not manipulate the header
    delivered_to = false
    received = false
    . . .

    Hier die Fehlermeldung die ich erhalte:
    . . .
    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‘, ’secmail@harnet.de‘)
    Logged from file getmail-ldap.py, line 179
    . . .

    Hast Du noch einen Tipp wo ich den Fehler suchen muss?

    Gruß von Stefan

  • Die Fehlermeldung bedeutet, dass die SMTP-Verbindung per TLS (verschlüsselt) stattfinden muss. Normalerweise sollte aber eine lokale Zustellung erfolgen (so zumindest in meinem Setup).

  • Stefan Harbich

    Hallo Markus,

    ich bin total am Verzweifeln. Ich versuche die Nachrichten mit sendmail an mein lokales Postfach weiterzuleiten. Leider ohne Erfolg. Es wird nur immer eine neue Nachricht zu meiner user@t-online Adresse gesendet. Nicht nach user@example.com. Egal was ich unter arguments einstelle. Ich weiß nicht mehr weiter.

    secmail@dsme01:~$ cat getmailrc_template.cfg
    [options]
    # for testing do not delete mails
    delete = false
    ## delete = true
    message_log = /var/log/getmail.log
    ## read_all = true
    read_all = false
    # do not manipulate the header
    delivered_to = false
    received = false

    [retriever]
    type =
    server =
    username =
    password =

    [destination]
    type = MDA_external
    path = /usr/sbin/sendmail
    arguments = („-bm“, „user@example.com“)
    unixfrom = true

    Irgendetwas aus dem Script „getmail-ldap.py“ scheint nicht zu funktionieren.

    Gruß von Stefan

  • Hallo Stefan,
    das Problem hat nichts mit dem getmail-Script zu tun, sondern mit deinem Mailrouting. Du musst sicherstellen, dass die E-Mail-Konfiguration so eingestellt ist, dass die Mails richtig zugestellt werden. Wenn du zum Beispiel die Mails für peter@gmail.com abrufen willst, dann muss der Mailversand von sendmail an peter@gmail.com an das lokale Postfach von peter@gmail.com zugestellt werden. Das läuft hier in dieser Konfiguration über exim>dovecot. Du musst dazu einen Weg finden für sendmail>dovecot. Siehe dazu auch die Tests am Ende meiner Konfiguration von Exim. Oder du versuchst, direkt einen Weg von getmail>dovecot-lda zu finden. Dann musst du das getmail-Script etwas anpassen.
    Viele Grüße
    Markus

  • Stefan Harbich

    Hallo Markus,
    ich musste mein Debian Server ein neues Update verpassen und nun läuft python in der Version 3.9 und das Skript „getmail-ldap.py“ funktioniert leider nicht mehr. Wo müsste ich mich informieren um das Skript auf Python 3 übersetzten zu können?
    Gruß von Stefan Harbich

Leave a Reply

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

  

  

  

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.