Zarafa spamtrain und UCS

nein…der dagent.log sagt nichts dazu…

Mon Apr 3 06:43:35 2017: [warning] [27382] renovate_encoding: unknown charset “cp-850”, skipping
Mon Apr 3 06:43:35 2017: [error ] [27382] HTML part not readable in any charset. Storing as attachment instead.
Mon Apr 3 17:18:47 2017: [warning] [ 3540] renovate_encoding: unknown charset “cp-850”, skipping
Mon Apr 3 17:18:47 2017: [error ] [ 3540] HTML part not readable in any charset. Storing as attachment instead.
Tue Apr 4 09:26:18 2017: [error ] [17556] Client disconnected
Tue Apr 4 09:26:18 2017: [error ] [17560] Client disconnected
Tue Apr 4 14:19:49 2017: [warning] [22406] renovate_encoding: reading data using charset “us-ascii” produced partial results: Invalid or incomplete multibyte or wide character
Wed Apr 5 14:47:11 2017: [ notice] [ 3370] LMTP service will now exit
Wed Apr 5 15:09:14 2017: [ notice] [ 3387] Starting kopano-dagent LMTP mode version 8,1,1,10 (10), pid 3387
Wed Apr 5 15:25:55 2017: [ notice] [ 3387] LMTP service will now exit
Wed Apr 5 15:25:55 2017: [ notice] [ 9095] Starting kopano-dagent LMTP mode version 8,1,1,10 (10), pid 9095
Wed Apr 5 15:29:10 2017: [ notice] [ 9095] LMTP service will now exit
Wed Apr 5 15:31:09 2017: [ notice] [ 3385] Starting kopano-dagent LMTP mode version 8,1,1,10 (10), pid 3385
Thu Apr 6 06:38:38 2017: [ notice] [ 3385] LMTP service will now exit
Thu Apr 6 07:13:04 2017: [ notice] [ 3367] Starting kopano-dagent LMTP mode version 8,1,1,10 (10), pid 3367
Thu Apr 6 08:03:45 2017: [ notice] [ 3367] LMTP service will now exit
Thu Apr 6 08:03:45 2017: [ notice] [25521] Starting kopano-dagent LMTP mode version 8,2,1,530 (530), pid 25521
Thu Apr 6 08:10:59 2017: [ notice] [25521] LMTP service will now exit
Thu Apr 6 08:12:22 2017: [ notice] [ 732] Starting kopano-dagent LMTP mode version 8,2,1,530 (530), pid 732

Mehr steht da nicht…echt merkwürdig…

Muss da ggf. der Loglevel hoch gesetzt werden…wenn ja, wo und/oder wie…(hab im Forum diesbezüglich nichts gefunden, nur dass Kollegen diesen mal auf 5 gesetzt hatten):

Update auf 4.2 gemacht?

Ich würde raten das Loglevel einmal zu erhöhen und dann eine Mail mit dem Teststring zuzustellen.

Ja, Update heute Morgen…hat aber nichts geändert…
Hab jetzt in /etc/kopano/dagent.cfg den Loglevel auf 5 und dann auf 6 gesetz und mit /etc/init.d/kopano-server restart kopano neu gestartet…im Logfile steht das gleiche wie vorher…

/etc/kopano/dagent.cfg den Loglevel auf 5 und dann auf 6 gesetz und mit /etc/init.d/kopano-server restart

in diesem Falle sollte auch kopano-dagent neugestartet werden (ein reload würde aber auch reichen). Für Änderungen die dauerhaft erfolgen sollen bietet es sich bei Univention eher an den Wert über die UCR zu verändern. Über die Konsole wäre das ein:

ucr set kopano/cfg/dagent/log_level=6

Danke Herr Bartels @fbartels nun hat es geklapt mit dem Log…können Sie daran was erkennen?

Email an mit zarafa migration Tool importierten Account:
Thu Apr  6 19:15:46 2017: [info   ] [17841] Accepted connection from [::ffff:127.0.0.1]:56768
Thu Apr  6 19:15:46 2017: [info   ] [18254] Starting worker for LMTP request pid 18254
Thu Apr  6 19:15:46 2017: [debug  ] [18254] PYTHONPATH = /usr/share/kopano-dagent/python
Thu Apr  6 19:15:47 2017: [debug  ] [18254] < 220 2.1.5 LMTP server is ready
Thu Apr  6 19:15:47 2017: [debug  ] [18254] > LHLO ucs.domain.intranet
Thu Apr  6 19:15:47 2017: [debug  ] [18254] LHLO ID: ucs.domain.intranet
Thu Apr  6 19:15:47 2017: [debug  ] [18254] < 250-SERVER ready
Thu Apr  6 19:15:47 2017: [debug  ] [18254] < 250-PIPELINING
Thu Apr  6 19:15:47 2017: [debug  ] [18254] < 250-ENHANCEDSTATUSCODE
Thu Apr  6 19:15:47 2017: [debug  ] [18254] < 250 RSET
Thu Apr  6 19:15:47 2017: [debug  ] [18254] > MAIL FROM:<testmailer2345@googlemail.com>
Thu Apr  6 19:15:47 2017: [debug  ] [18254] < 250 2.1.0 Ok
Thu Apr  6 19:15:47 2017: [debug  ] [18254] > RCPT TO:<mail@user-domain.de>
Thu Apr  6 19:15:47 2017: [debug  ] [18254] Resolved command "RCPT TO:<mail@user-domain.de>" to recipient address "mail@user-domain.de"
Thu Apr  6 19:15:47 2017: [notice ] [18254] Resolved recipient mail@user-domain.de as user userdomain
Thu Apr  6 19:15:47 2017: [debug  ] [18254] < 250 2.1.5 Ok
Thu Apr  6 19:15:47 2017: [debug  ] [18254] > DATA
Thu Apr  6 19:15:47 2017: [debug  ] [18254] < 354 2.1.5 Start mail input; end with <CRLF>.<CRLF>
Thu Apr  6 19:15:47 2017: [info   ] [18254] * Loading plugins started
Thu Apr  6 19:15:47 2017: [info   ] [18254] ** Checking plugins in /var/lib/kopano/dagent/plugins
Thu Apr  6 19:15:47 2017: [info   ] [18254] * Loading plugins done
Thu Apr  6 19:15:47 2017: [info   ] [18254] Mail will be delivered in Inbox
Thu Apr  6 19:15:47 2017: [debug  ] [18254] Trying to parse alternative multipart 1 of mail body
Thu Apr  6 19:15:47 2017: [debug  ] [18254] HTML document contains no HEAD tag
Thu Apr  6 19:15:47 2017: [debug  ] [18254] Charset is "UTF-8" (case #8).
Thu Apr  6 19:15:47 2017: [debug  ] [18254] renovate_encoding: reading data using charset "UTF-8" succeeded.
Thu Apr  6 19:15:47 2017: [info   ] [18254] * PostConverting processing started
Thu Apr  6 19:15:47 2017: [info   ] [18254] * PostConverting processing done
Thu Apr  6 19:15:47 2017: [info   ] [18254] * PreDelivery processing started
Thu Apr  6 19:15:47 2017: [info   ] [18254] * PreDelivery processing done
Thu Apr  6 19:15:47 2017: [info   ] [18254] * PreRuleProcess processing started
Thu Apr  6 19:15:47 2017: [info   ] [18254] * PreRuleProcess processing done
Thu Apr  6 19:15:47 2017: [debug  ] [18254] Processing rule Bahn Tickets for userdomain
Thu Apr  6 19:15:47 2017: [info   ] [18254] Rule Bahn Tickets doesn't match: 0x8004010f
Thu Apr  6 19:15:47 2017: [debug  ] [18254] Processing rule Tipp24 Quittungen for userdomain
Thu Apr  6 19:15:47 2017: [info   ] [18254] Rule Tipp24 Quittungen doesn't match: 0x8004010f
Thu Apr  6 19:15:47 2017: [debug  ] [18254] Target user has OOF inactive

Thu Apr  6 19:15:47 2017: [info   ] [18254] * PostDelivery processing started
Thu Apr  6 19:15:47 2017: [info   ] [18254] * PostDelivery processing done
Thu Apr  6 19:15:47 2017: [info   ] [18254] * SendNewMailNotify processing started
Thu Apr  6 19:15:47 2017: [info   ] [18254] * SendNewMailNotify processing done
Thu Apr  6 19:15:47 2017: [debug  ] [18254] Send 'New Mail' notification
Thu Apr  6 19:15:47 2017: [info   ] [18254] Delivered message to 'userdomain', Subject: "dagent test", Message-Id: <CAGran6nr5NTCQisEvQKT0sKBBf1Px_8bvzVk57pwWvxPT-mNjQ@mail.gmail.com>, size 4581
Thu Apr  6 19:15:47 2017: [info   ] [18254] Finished processing message
Thu Apr  6 19:15:47 2017: [debug  ] [18254] < 250 2.1.5 mail@user-domain.de Ok
Thu Apr  6 19:15:47 2017: [debug  ] [10499] > QUIT
Thu Apr  6 19:15:47 2017: [debug  ] [10499] < 221 2.0.0 Bye
Thu Apr  6 19:15:47 2017: [info   ] [10499] LMTP thread exiting


Testmail an neu angelegten User ohne Import von Daten:

Thu Apr  6 19:39:22 2017: [info   ] [18655] Accepted connection from [::ffff:127.0.0.1]:33186
Thu Apr  6 19:39:22 2017: [info   ] [18763] Starting worker for LMTP request pid 18763
Thu Apr  6 19:39:22 2017: [debug  ] [18763] PYTHONPATH = /usr/share/kopano-dagent/python
Thu Apr  6 19:39:22 2017: [debug  ] [18763] < 220 2.1.5 LMTP server is ready
Thu Apr  6 19:39:22 2017: [debug  ] [18763] > LHLO ucs.domain.intranet
Thu Apr  6 19:39:22 2017: [debug  ] [18763] LHLO ID: ucs.domain.intranet
Thu Apr  6 19:39:22 2017: [debug  ] [18763] < 250-SERVER ready
Thu Apr  6 19:39:22 2017: [debug  ] [18763] < 250-PIPELINING
Thu Apr  6 19:39:22 2017: [debug  ] [18763] < 250-ENHANCEDSTATUSCODE
Thu Apr  6 19:39:22 2017: [debug  ] [18763] < 250 RSET
Thu Apr  6 19:39:22 2017: [debug  ] [18763] > MAIL FROM:<testmailer2345@googlemail.com>
Thu Apr  6 19:39:22 2017: [debug  ] [18763] < 250 2.1.0 Ok
Thu Apr  6 19:39:22 2017: [debug  ] [18763] > RCPT TO:<ludwigtest@domain.intranet>
Thu Apr  6 19:39:22 2017: [debug  ] [18763] Resolved command "RCPT TO:<ludwigtest@domain.intranet>" to recipient address "ludwigtest@domain.intranet"
Thu Apr  6 19:39:22 2017: [notice ] [18763] Resolved recipient ludwigtest@domain.intranet as user ludwigtest
Thu Apr  6 19:39:22 2017: [debug  ] [18763] < 250 2.1.5 Ok
Thu Apr  6 19:39:22 2017: [debug  ] [18763] > DATA
                                                                  43,1          62%

Ist auch merkwürdig, dass bei dem Account in dem funktioniert viel weniger Logdaten sind (bis auf die Filter, was klar ist),
Mit freundlichen Grüßen Holger

hört die zweite Zustellung wirklich bei

Thu Apr 6 19:39:22 2017: [debug ] [18763] > DATA

auf?

Bis zu diesem Zeitpunkt sind die Logausgaben (bis auf Zeitstempel und Adressen) identisch.

Hier noch mal das neue Log von dem Account in dem es funktioniert und der keine Importierten Daten enthält:

Tue Apr 11 12:16:50 2017: [info   ] Maximum LMTP threads set to 20
Tue Apr 11 12:16:50 2017: [info   ] Listening on port 2003 for LMTP
Tue Apr 11 12:16:50 2017: [info   ] [10381] Logger process started on pid 10396
Tue Apr 11 12:16:50 2017: [debug  ] [10396] Log signal thread started
Tue Apr 11 12:16:50 2017: [debug  ] [10381] StatsClient binding socket
Tue Apr 11 12:16:50 2017: [debug  ] [10381] StatsClient bound socket to /tmp/.7c1587116c6b4ebf.sock
Tue Apr 11 12:16:50 2017: [ notice] [10381] Starting kopano-dagent LMTP mode version 8,2,1,530 (530), pid 10381
Tue Apr 11 12:18:44 2017: [info   ] [10381] Accepted connection from [::ffff:127.0.0.1]:49328
Tue Apr 11 12:18:44 2017: [info   ] [10442] Starting worker for LMTP request pid 10442
Tue Apr 11 12:18:44 2017: [debug  ] [10442] PYTHONPATH = /usr/share/kopano-dagent/python
Tue Apr 11 12:18:44 2017: [debug  ] [10442] < 220 2.1.5 LMTP server is ready
Tue Apr 11 12:18:44 2017: [debug  ] [10442] > LHLO ucs.domain.intranet
Tue Apr 11 12:18:44 2017: [debug  ] [10442] LHLO ID: ucs.domain.intranet
Tue Apr 11 12:18:44 2017: [debug  ] [10442] < 250-SERVER ready
Tue Apr 11 12:18:44 2017: [debug  ] [10442] < 250-PIPELINING
Tue Apr 11 12:18:44 2017: [debug  ] [10442] < 250-ENHANCEDSTATUSCODE
Tue Apr 11 12:18:44 2017: [debug  ] [10442] < 250 RSET
Tue Apr 11 12:18:44 2017: [debug  ] [10442] > MAIL FROM:<tm@googlemail.com>
Tue Apr 11 12:18:44 2017: [debug  ] [10442] < 250 2.1.0 Ok
Tue Apr 11 12:18:44 2017: [debug  ] [10442] > RCPT TO:<ludwigtest@domain.intranet>
Tue Apr 11 12:18:44 2017: [debug  ] [10442] Resolved command "RCPT TO:<ludwigtest@domain.intranet>" to recipient address "ludwigtest@domain.intranet"
Tue Apr 11 12:18:44 2017: [notice ] [10442] Resolved recipient ludwigtest@domain.intranet as user ludwigtest
Tue Apr 11 12:18:44 2017: [debug  ] [10442] < 250 2.1.5 Ok
Tue Apr 11 12:18:44 2017: [debug  ] [10442] > DATA
Tue Apr 11 12:18:44 2017: [debug  ] [10442] < 354 2.1.5 Start mail input; end with <CRLF>.<CRLF>
Tue Apr 11 12:18:44 2017: [info   ] [10442] * Loading plugins started
Tue Apr 11 12:18:44 2017: [info   ] [10442] ** Checking plugins in /var/lib/kopano/dagent/plugins
Tue Apr 11 12:18:44 2017: [info   ] [10442] * Loading plugins done
Tue Apr 11 12:18:44 2017: [info   ] [10442] Spam marker found in e-mail, delivering to junk-mail folder
Tue Apr 11 12:18:44 2017: [info   ] [10442] Mail will be delivered in junkmail folder
Tue Apr 11 12:18:44 2017: [debug  ] [10442] Trying to parse alternative multipart 1 of mail body
Tue Apr 11 12:18:44 2017: [debug  ] [10442] HTML document contains no HEAD tag
Tue Apr 11 12:18:44 2017: [debug  ] [10442] Charset is "UTF-8" (case #8).
Tue Apr 11 12:18:44 2017: [debug  ] [10442] renovate_encoding: reading data using charset "UTF-8" succeeded.
Tue Apr 11 12:18:44 2017: [info   ] [10442] * PostConverting processing started
Tue Apr 11 12:18:44 2017: [info   ] [10442] * PostConverting processing done
Tue Apr 11 12:18:44 2017: [info   ] [10442] * PreDelivery processing started
Tue Apr 11 12:18:44 2017: [info   ] [10442] * PreDelivery processing done
Tue Apr 11 12:18:44 2017: [info   ] [10442] * PostDelivery processing started
Tue Apr 11 12:18:44 2017: [info   ] [10442] * PostDelivery processing done
Tue Apr 11 12:18:44 2017: [info   ] [10442] * SendNewMailNotify processing started
Tue Apr 11 12:18:44 2017: [info   ] [10442] * SendNewMailNotify processing done
Tue Apr 11 12:18:44 2017: [debug  ] [10442] Send 'New Mail' notification
Tue Apr 11 12:18:44 2017: [info   ] [10442] Delivered message to 'ludwigtest', Subject: "***SPAM***test11.04", Message-Id: <CAGran6mxr+8L5mCz4Y=1vUVX2-HbO1Xh+1D6e4nQ_V+GOBZLyA@mail.gmail.com>, size 5389
Tue Apr 11 12:18:44 2017: [info   ] [10442] Finished processing message
Tue Apr 11 12:18:44 2017: [debug  ] [10442] < 250 2.1.5 ludwigtest@domain.intranet Ok
Tue Apr 11 12:18:44 2017: [debug  ] [10442] > QUIT
Tue Apr 11 12:18:44 2017: [debug  ] [10442] < 221 2.0.0 Bye
Tue Apr 11 12:18:44 2017: [info   ] [10442] LMTP thread exiting
                                                                   1,1        Anfang

Wie es aussieht, wird in der einen Mail * * * SPAM * * * nicht gesetzt.
Kann sein dass beim kopieren des Logs was abgeschnitten wurde…entschuldigen Sie…

Noch jemand eine Idee zu meinen letzten Posts?
Danke Holger

Hallo @fbartels,

leider ist das genannte Script nicht mehr abrufbar. Wäre es möglich, dass Sie es hier noch einmal posten? Oder ist es mittlerweile obsolet?

Vielen Dank & beste Grüsse!

eine aktualisierte Version gibt es unter https://kb.kopano.io/display/WIKI/Kopano-spamd

Vielen Dank @fbartels!

Ich habe das Script um folgende Features erweitert:

  • Lernen von Spam UND Ham möglich
  • Lernen aus zwei unabhängigen, im spamd.conf global konfigurierbaren Ordnern (standardmässig “LearnHam” und “LearnSpam” -> wird eine Mail in diesen Ordner verschoben, wird sie entsprechend angelernt
  • Prüfung auf den Spam-Header habe ich entfernt, da sie in diesem Szenario imho nicht mehr nötig ist

 
Das oben genannte funktioniert, allerdings habe ich noch zwei Punkte, bei denen ich eure Hilfe benötige:

  1. Nach dem Anlernen der Mail würde ich diese gerne automatisch in einen anderen Ordner verschieben (LearnHam -> Inbox und LearnSpam -> Junk). Dies dürfte dem gängisten Workflow entsprechen und ist quasi die Bestätigung für das erfolgreiche Lernen. Die notwendige Variable (targetfolder) wird in kopano-spamd.py bereits befüllt, allerdings schlägt die move-Methode auf dem Item-Objekt fehl (Aufruf item.move(targetfolder) > Logfile: ‘Item’ object has no attribute ‘move’). Daher habe ich die entsprechende Zeile (Klasse Checker, Methode Learn) aktuell noch auskommentiert. Gemäss Python-Kopano-Dokumentation sollte diese Methode auf dem Item-Objekt jedoch definiert sein. @fbartels: Können Sie mir hier vielleicht weiterhelfen?
  2. Der Service startet aktuell noch nicht automatisch, sondern muss manuell über die Konsole aufgerufen werden (python /usr/local/bin/kopano-spamd.py). Ich würde jedoch gerne realisieren, dass der Service mit Kopano startet und beim Beenden von Kopano gestoppt wird. Wie lässt sich das am besten realisieren?

 
kopano-spamd.py:

#!/usr/bin/env python
# coding=utf-8
"""
ICS driven spam learning daemon for Kopano / SpamAssasin
See included readme.md for more information.
"""
import shlex
import subprocess
import time
import kopano
from MAPI.Tags import *
from kopano import Config, log_exc

CONFIG = {
	'run_as_user': Config.string(default="kopano"),
	'run_as_group': Config.string(default="kopano"),
	'learncmdspam': Config.string(default="/usr/bin/sudo -u amavis /usr/bin/sa-learn --spam"),
	'learncmdham': Config.string(default="/usr/bin/sudo -u amavis /usr/bin/sa-learn --ham"),
	'spamfolder': Config.string(default="LearnSpam"),
	'hamfolder': Config.string(default="LearnHam")
}


class Service(kopano.Service):
	def main(self):
		server = self.server
		state = server.state
		catcher = Checker(self)
		with log_exc(self.log):
			while True:
				try:
					state = server.sync(catcher, state)
				except Exception as e:
					if e.hr == MAPI_E_NETWORK_ERROR:
						self.log.info('Trying to reconnect to Server in %s seconds' % 5)
					else:
						self.log.info('Error: [%s]' % e)
					time.sleep(5)
				time.sleep(1)


class Checker(object):
	def __init__(self, service):
		self.log = service.log
		self.learncmdspam = service.config['learncmdspam']
		self.learncmdham = service.config['learncmdham']
		self.spamfolder = service.config['spamfolder']
		self.hamfolder = service.config['hamfolder']

	def update(self, item, flags):
		if item.message_class == 'IPM.Note':
			if item.folder == item.store.user.folder(self.spamfolder):
				self.learn(item, 'spam')
			elif item.folder == item.store.user.folder(self.hamfolder):
				self.learn(item, 'ham')

	def learn(self, item, learntype):
		with log_exc(self.log):
			try:
				spameml = item.eml()
				if learntype == 'spam':
					learncmd = self.learncmdspam
					targetfolder = item.store.user.junk
				elif learntype == 'ham':
					learncmd = self.learncmdspam
					targetfolder = item.store.user.inbox
				havespam = True
			except Exception as e:
				self.log.info('Failed to extract eml of email: [%s] [%s]' % (e, item.entryid))
			if havespam and learncmd and targetfolder:
				try:
					p = subprocess.Popen(shlex.split(learncmd), stdin=subprocess.PIPE, stdout=subprocess.PIPE)
					learning, output_err = p.communicate(spameml)
					self.log.info('[%s] sa-learn %s: %s' % (item.store.user.name, learntype, learning.strip('\n')))
					#item.move(targetfolder)
				except Exception as e:
					self.log.info('sa-learn failed: [%s] [%s]' % (e, item.entryid))


def main():
	parser = kopano.parser('ckpsF')  # select common cmd-line options
	options, args = parser.parse_args()
	service = Service('spamd', config=CONFIG, options=options)
	service.start()


if __name__ == '__main__':
	main()

 
spamd.cfg:

##############################################################
# SPAMD SERVICE SETTINGS

# run as specific user
#run_as_user         = kopano

# run as specific group
#run_as_group        = kopano

# control pid file
pid_file            =   /var/run/kopano/spamd.pid

# run server in this path (when not using the -F switch)
#running_path = /var/lib/kopano

##############################################################
# LOG SETTINGS

# Logging method (syslog, file)
log_method          =   file

# Loglevel (0(none), 1(crit), 2(err), 3(warn), 4(notice), 5(info), 6(debug))
#log_level           =   3

# Logfile for log_method = file, use '-' for stderr
log_file            =   /var/log/kopano/spamd.log

# Log timestamp - prefix each log line with timestamp in 'file' logging mode
log_timestamp       =   1

###############################################################
# SPAMD Specific settings

learncmdspam = /usr/bin/sudo -u amavis /usr/bin/sa-learn --spam
learncmdham = /usr/bin/sudo -u amavis /usr/bin/sa-learn --ham
spamfolder = LearnSpam
hamfolder = LearnHam

 
Installationsanleitung: https://kb.kopano.io/display/WIKI/Kopano-spamd

Hi @nkauf,

für den automatischen Start fallen mir zwei Wege ein: entweder das Skript einfach mittels rc.local beim Systemstart machen (oder @reboot cron taks) oder eine Systemd Unit hierfür schreiben.

Wir sind gerade auch dabei ein solches Skript in die eigentlichen Pakete zu integrieren, das Skript ist soweit schon Teil des nächsten Releases, etwas Skripting drum herum kommt eventuell erst zum folgenden Release. Das Ticket hierzu ist https://jira.kopano.io/browse/KC-666.

Für die Python Fragen würde ich empfehlen ein Topic im Kopano Forum zu eröffnen (dann auf englisch).

Hi @fbartels,

vielen Dank! Dann werde ich mal einen reboot cronjob versuchen. Wenn das Script bis dahin sauber läuft könnt ihr gerne auch meine Erweiterung in den Release einfliessen lassen, falls ihr meinen Ansatz für brauchbar haltet. Ham Training war ja hier ein mehrfach gewünschtes Feature.

Topic habe ich eröffnet: https://forum.kopano.io/topic/971/kopano-python-item-move-not-working-method-undefined-error

Beste Grüsse!

Hier nun das komplette Script mit funktionierender Verschiebung nach dem Lernen, falls jemand von euch dies so einsetzen möchte:

kopano-spamd.py:

#!/usr/bin/env python
# coding=utf-8
"""
ICS driven spam learning daemon for Kopano / SpamAssasin
See included readme.md for more information.
"""
import shlex
import subprocess
import time
import kopano
from MAPI.Tags import *
from kopano import Config, log_exc

CONFIG = {
	'run_as_user': Config.string(default="kopano"),
	'run_as_group': Config.string(default="kopano"),
	'learncmdspam': Config.string(default="/usr/bin/sudo -u amavis /usr/bin/sa-learn --spam"),
	'learncmdham': Config.string(default="/usr/bin/sudo -u amavis /usr/bin/sa-learn --ham"),
	'spamfolder': Config.string(default="LearnSpam"),
	'hamfolder': Config.string(default="LearnHam")
}


class Service(kopano.Service):
	def main(self):
		server = self.server
		state = server.state
		catcher = Checker(self)
		with log_exc(self.log):
			while True:
				try:
					state = server.sync(catcher, state)
				except Exception as e:
					if e.hr == MAPI_E_NETWORK_ERROR:
						self.log.info('Trying to reconnect to Server in %s seconds' % 5)
					else:
						self.log.info('Error: [%s]' % e)
					time.sleep(5)
				time.sleep(1)


class Checker(object):
	def __init__(self, service):
		self.log = service.log
		self.learncmdspam = service.config['learncmdspam']
		self.learncmdham = service.config['learncmdham']
		self.spamfolder = service.config['spamfolder']
		self.hamfolder = service.config['hamfolder']

	def update(self, item, flags):
		if item.message_class == 'IPM.Note':
			if item.folder == item.store.user.folder(self.spamfolder):
				self.learn(item, 'spam')
			elif item.folder == item.store.user.folder(self.hamfolder):
				self.learn(item, 'ham')

	def learn(self, item, learntype):
		with log_exc(self.log):
			try:
				spameml = item.eml()
				if learntype == 'spam':
					learncmd = self.learncmdspam
					targetfolder = item.store.user.junk
				elif learntype == 'ham':
					learncmd = self.learncmdspam
					targetfolder = item.store.user.inbox
				havespam = True
			except Exception as e:
				self.log.info('Failed to extract eml of email: [%s] [%s]' % (e, item.entryid))
			if havespam and learncmd and targetfolder:
				try:
					p = subprocess.Popen(shlex.split(learncmd), stdin=subprocess.PIPE, stdout=subprocess.PIPE)
					learning, output_err = p.communicate(spameml)
					self.log.info('[%s] sa-learn %s: %s' % (item.store.user.name, learntype, learning.strip('\n')))
					item.folder.move(item, targetfolder)
				except Exception as e:
					self.log.info('sa-learn failed: [%s] [%s]' % (e, item.entryid))


def main():
	parser = kopano.parser('ckpsF')  # select common cmd-line options
	options, args = parser.parse_args()
	service = Service('spamd', config=CONFIG, options=options)
	service.start()


if __name__ == '__main__':
	main()

spamd.cfg:

##############################################################
# SPAMD SERVICE SETTINGS

# run as specific user
#run_as_user         = kopano

# run as specific group
#run_as_group        = kopano

# control pid file
pid_file            =   /var/run/kopano/spamd.pid

# run server in this path (when not using the -F switch)
#running_path = /var/lib/kopano

##############################################################
# LOG SETTINGS

# Logging method (syslog, file)
log_method          =   file

# Loglevel (0(none), 1(crit), 2(err), 3(warn), 4(notice), 5(info), 6(debug))
#log_level           =   3

# Logfile for log_method = file, use '-' for stderr
log_file            =   /var/log/kopano/spamd.log

# Log timestamp - prefix each log line with timestamp in 'file' logging mode
log_timestamp       =   1

###############################################################
# SPAMD Specific settings

learncmdspam = /usr/bin/sudo -u amavis /usr/bin/sa-learn --spam
learncmdham = /usr/bin/sudo -u amavis /usr/bin/sa-learn --ham
spamfolder = LearnSpam
hamfolder = LearnHam

Installationsanleitung immer noch gemäss der Original-Lösung: https://kb.kopano.io/display/WIKI/Kopano-spamd

Vielen Dank nochmal @fbartels!

Hallo hab es soweit gemacht wie beschrieben, bekomme aber folgende Fehlermedung im Log:

2018-01-31 20:03:00,430 - spamd - ERROR - Traceback (most recent call last):
  File "/usr/lib/python2.7/dist-packages/kopano/utils.py", line 115, in ImportMessageChange
    self.importer.update(item, flags)
  File "/usr/local/bin/kopano-spamd.py", line 52, in update
    if item.folder == item.store.user.folder(self.spamfolder):
  File "/usr/lib/python2.7/dist-packages/kopano/store.py", line 301, in folder
    return self.subtree.folder(path, recurse=recurse, create=create)
  File "/usr/lib/python2.7/dist-packages/kopano/folder.py", line 376, in folder
    raise NotFoundError("no such folder: '%s'" % path)
NotFoundError: no such folder: 'LearnSpam'

2018-01-31 20:06:24,414 - spamd - ERROR - could not process change for entryid 000000006A6B4254BC944219AD4D918246E2D7CF0100000005000000C0D89BBCD8B24B3998FF9C9C4F65A20200000000 ([SPropValue(0x67110003, 323466L), SPropValue(0x6715000A, 2147746063L), SPropValue(0x0FFA0102, 'jkBT\xbc\x94B\x19\xadM\x91\x82F\xe2\xd7\xcf')]):
2018-01-31 20:06:24,415 - spamd - ERROR - Traceback (most recent call last):
  File "/usr/lib/python2.7/dist-packages/kopano/utils.py", line 115, in ImportMessageChange
    self.importer.update(item, flags)
  File "/usr/local/bin/kopano-spamd.py", line 52, in update
    if item.folder == item.store.user.folder(self.spamfolder):
  File "/usr/lib/python2.7/dist-packages/kopano/store.py", line 301, in folder
    return self.subtree.folder(path, recurse=recurse, create=create)
  File "/usr/lib/python2.7/dist-packages/kopano/folder.py", line 376, in folder
    raise NotFoundError("no such folder: '%s'" % path)
NotFoundError: no such folder: 'LearnSpam'

Hallo @gonzo0815

Hast Du auch die in der Config benannten Ordner (“LearnHam” und “LearnSpam”) angelegt? Diese müssen sich auf der obersten Ebene des Postfachs befinden.

Ich vermerke mir: Da das Anlegen der Folder manuell geschieht wäre es ggf. sinnvoll, den Fehler abzufangen und ohne Logeintrag zu handhaben, falls ein Nutzer die Ordner nicht anlegt oder löscht. Sonst läuft der Log mit diesen Fehlern voll. Wenn jemand Lust hat kann er das ergänzen, ansonsten versuche ich mich daran, wenn ich das Script das nächste mal anfasse.

Beste Grüsse!

Hallo
danke für den Hinweis.
Könntest du mir bitte sagen wo das Standard Verzeichnis liegt?

Danke

Hallo @gonzo0815

Lege einfach im jeweiligen Postfach zwei Ordner an (“LearnHam” und “LearnSpam”) - z.B. via Kopano Webapp: Rechtsklick in der Ordnerliste der Ansicht “Mail” auf den Namen des Postfachinhabers -> Neuer Ordner

Du kannst die Ordner auch anders benennen bzw. in einem Unterordner erstellen, musst dann aber die spamd.cfg entsprechend anpassen (Varablen “spamfolder” und “hamfolder”).

Wenn Du mehrere Benutzer hast musst Du sicherstellen, dass diese Ordner in jedem Postfach existieren. Andernfalls siehst Du die von Dir genannten Fehlermeldungen im Log.

Beste Grüsse!

Mastodon