Nutzen von Notify

Eine Konfiguration für wenige User

 Wenn der Mailfilter des Hamsters eine Mail ignoriert, statt sie zu laden oder zu löschen, so sind irgendwann weitere Aktionen notwendig. Ist die Mail Spam oder aus anderen Gründen unerwünscht, so muß sie irgendwann aus dem Postfach gelöscht werden. Bei den meisten Providern kann das über ein Webinterface getan werden, so auch bei mir. Daher biete ich hier keine Automatik oder besonders komfortable Lösungen.

 Vielmehr zielt dieses kleine Script auf den Fall weniger User (z.B. Familie) ab. Die eigentlichen Empfänger können immer noch am besten Feststellen, ob sie eine bestimmte Mail erhalten wollen oder nicht. Falls ja, muß nur der Notify mit Zitat beantwortet werden, was jeder Client schaffen sollte. Das Script unten bietet für diesen Fall eine einfache Option. Es kann damit auch die fragliche Mail gelöscht werden. Typischerweise wird das aber mindestens einmal vergessen, so daß der Administrator doch wieder Handarbeit anwenden darf. Das Ziel ist eben, daß die letztlichen User es einfach haben.

Hier zunächst das Script, die weiteren Erläuterungen folgen danach. Ausgearbeitet und getestet wurde es mit den aktuellen (1.3.23.140ff.) Versionen. Ein Einsatz unter 1.3.23.4 wurde nicht probiert.

UseNotify.hsc
#!hs2
#!load hamster.hsm

#**********************************************************************
# usenotify.hsc
# This script will enable the user to simply load (and kill) mails
# from the filter. It is assumed the mailfilt.hst will send a notify
# to the original recipient when a mail is ignored. The user can reply
# to this notify, and the mail is load with the next mail poll.
#**********************************************************************
# A special mailaccount has to be created (see $notifyfrom), which is
# aliased as the origin of the notifies. This script will read all
# *.msg in this account.
# The Message-ID of the mail is extracted, and used as the criteria in
# mailfilt.hst. Since my POP3 servers will add an ID if none exists,
# this is sufficient enough. The ID is placed in an [*]-section at
# the *begin* of mailfilt.hst. There is no problem with other filters
# for ignore, since this section is used first.
# The final user receives a notify about an ignored mail. Now she can
# ignore this notify, then the mail will be killed later on the server
# (this is specific to my configuration). Or she can answer the notify,
# in this case a =load instruction is assumed. The third option is to
# change the subject to start with ==kill, in this case the mail will
# be killed by mailfilt.hst
#**********************************************************************

varset ($notifyfrom, HamMailPath+"usenotify")    # [1]
varset ($mailfilthst, HamPath+"mailfilt.hst")
var ($Allmails, $mailfilt)
var ($k, $N, $aMail,  $Subj, $filter, $comment)

$Allmails = ListAlloc
$mailfilt = ListAlloc
ListFiles( $Allmails, $notifyfrom+"\*.msg", true)
$N = ListCount($Allmails)
If ($N>0)
  ListLoad ($mailfilt, $mailfilthst)
  If (ListGet($mailfilt, 0) != "[*]")            # [2]
    ListInsert ($mailfilt, 0, "[*]")
    ListInsert ($mailfilt, 1)
  endif
  For ($k, 0, ListCount($Allmails)-1)
    $aMail = ListGet ($Allmails, $k)
    Extract ($aMail, $Subj, $filter, $comment)   # [3]
    If (RE_Match( $Subj, "^==kill\b"))           # [4]
      ListInsert($mailfilt, 1, "=kill() "+$filter +$Comment)
      Print ("kill "+$filter)
    else
     If (RE_Match( $Subj, "^==load\b"))
      ListInsert($mailfilt, 1, "=load() "+$filter +$Comment)
      Print ("load "+$filter)
     else
      ListInsert($mailfilt, 1, "=load() "+$filter +$Comment)
      Print ("load "+$filter)
     endif
    endif
    FileDelete($aMail)
  endfor
  ListSave ($mailfilt, $mailfilthst)             # [5]
  HamMessage ($HAM_MSG_RELOADCONFIG, 1)
endif
ListFree($mailfilt)
ListFree($Allmails)

quit

sub Extract($mail, *$Subj, *$filter, *$comment)
  varset ($subjre, "^>? *subject:")
  varset ($midre,  "^>? *message\-id:")
  varset ($fromre, "^>? *From:\s")
  varset ($Datere, "^Date:\s")
  varset ($Header, True)
  var ($theMail, $line, $ln, $N)
  varset ($p, $a, $HFrom, $Date, $BFrom, $BSubj, $BMID, "")
  $Subj = ""                    # ==kill oder == load erkennen      (Header) 
  $Date = ""                    # Von wann ist die Anforderung      (Header)
  $filter = "#"                 # vermeidet leere MID als Kriterium
  $BFrom = ""                   # Wer hatte das geschickt           (Body)
  $BSubj = ""                   # Welches Subject hatte die Mail?   (Body)
  $BMID = ""                    # Welche Message-ID hatte die Mail? (Body)
  $theMail = ListAlloc
  ListLoad ($theMail, $mail)
  $N = ListCount($theMail)-1
  for ($ln, 0, $N)
    $line = ListGet($theMail, $ln)
    If (""==$line)
      $Header = False
    endif
    If ($Header)                                  # [6]
      If (RE_Match( $line, $subjre) && ($Subj=""))
        RE_Parse( $line, "(\S+:)\s+(.*)", $a, $Subj )
      endif
      If (RE_Match( $line, $datere) && ($Date=""))
        RE_Parse( $line, "(\S+:)\s+(.*)", $a, $Date )
      endif
      If (RE_Match( $line, $fromre) && ($HFrom=""))
        RE_Parse( $line, "(\S+:)\s+(.*)", $a, $HFrom )
      endif
    endif
    If (!$Header)                                 # [7]
      If (RE_Match( $line, $midre))
        $BMID = RE_Extract( $line, "\<.+@.+\>" )
      endif
      If (RE_Match( $line, $fromre) && ($BFrom=""))
        RE_Parse( $line, "(\S+:)\s+(.*)", $a, $BFrom )
      endif
      If (RE_Match( $line, $subjre) && ($BSubj=""))
        RE_Parse( $line, "(\S+:)\s+(.*)", $a, $BSubj )
      endif
    endif
  endfor
  If ($BFrom != "")                               # [8]
    $filter = "From: " + chr(34)+$BFrom+chr(34)
  endif
  If ($BSubj != "")
    $filter = "Subject: " + chr(34)+$BSubj+chr(34)
  endif
  If ($BMID != "")
    $filter = "Message-ID: " + chr(34)+$BMID+chr(34)
  endif
  $comment = " # "+$Date+" | "+$HFrom
  ListFree ($theMail)
endsub
 

 Schritt # [1] Zunächst einmal muß im Hamster ein lokaler Account eingerichtet werden, der die Anweisungen empfangen soll. Bei mir gibt es einen FQDN, daher tragen die Notifies als Absender
From: "Hamster-Info" <local-hamster-info@ham.soscha.de>
Die Antwort des Users auf diese Mail soll in den neuen Account geleitet werden. Daher ist noch ein Eintrag in der MAlias.hst notwendig
local-hamster-info@%FQDN%=usenotify
Natürlich kann auch direkt ein passendes Postfach eingerichtet werden; das ist Geschmackssache.

 Dann muß dieses Script noch als Action in der Hamster.ini eingerichtet werden. Es wird aufgerufen, wenn eine Mail für den Account eintrifft:
[Actions]
mail.local.usenotify.script=usenotify.hsc

Der User findet in seinem Postfach eine Nachricht des Hamsters über eine ignorierte Mail. Absendeadresse und Subject ist dort sichtbar, sowie der Anfang des Textes. In der Regel reicht das nach kurzer Erläuterung aus, eine Entscheidung zu triffen. Ist die Mail erwünscht, so muß die Nachricht einfach beantwortet werden. Der Notify wird dabei zitiert. Ob die Zitate korrekt gequotet werden (mit ">") oder nicht, sollte keine Rolle spielen. Diese Antwort geht an den Hamster.

 Der Hamster ruft per Action usenotify.hsc auf. Das Script bearbeitet alle *.msg im Postfach, als reine Sicherheitsmaßnahme. Normalerweise liegt nur eine Mail vor.

 Schritt # [2] Die Mailfilter werden geladen. Es wird sichergestellt, daß ganz am Anfang der Datei ein Abschnitt [*] existiert. Dieser darf mehrfach vorkommen, so daß kein Schaden angerichtet wird.

 Schritt # [3] Die Mail wird geladen, und auf Filterkriterien und den Absender untersucht. Außerdem wird noch ermittelt, welchen Wunsch der Absender eingetragen hat.

 Schritt # [4] Je nach Ergebnis wird ein passender Eintrag oben in der Mailfilt.hst erstellt. Dieser sorgt dafür, daß beim nächsten Mailabruf die fragliche Mail geladen bzw. gelöscht wird. Das wird dadurch geregelt, daß der Absender an den Anfang des Subject eine Markierung schriebt. "==load" bewirkt ein Nachladen, "==kill" entsprechend ein Löschen. Ohne spezielles Kennwort tritt der Default-Fall ein, und das ist ebenfalls nachladen.

 Schritt # [5] Die modifizierte Mailfilt.hst wird gespeichert. Wie man hier schon sehen kann, sind keinerlei Sicherungen eingebaut. Wird diese Option genutzt, während der Administrator die Datei editiert, geht der Eintrag verloren. Auch könnten merkwürdige Ergebnisse auftreten, wenn die Option während eines Mailabrufes genutzt wird. Schlimmstenfalls allerdings wird die Mail eben nicht abgerufen, ohne daß sie verloren geht.

 Schritt # [6] Aus dem Header der Antwort werden Subject:, Date: und From: ermittelt.

 Schritt # [7] Aus dem Body der Antwort werden Message-ID:, From: und Date: der ignorierten Mail ermittelt. Beides arbeitet mit RegExp, um gerade bei diesem Schritt von Quote oder nicht unabhängig zu sein. Wessen Client ungewähnliche Quote-Marker setzt, der kann hier die RegExp erweitern.

 Schritt # [8] Für den Filter zum Nachladen werden die Merkmale Message-ID:, Subject: und From: verwendet, und zwar in dieser Priorität. Liegt also keine Message-ID: vor, so wird Subject: eingetragen. Fehlt auch dieses, so muß der Absender herhalten. Hinter den Filter kommt dann noch als Kommentar Datum und Absender des Nachladeauftrags.

 Der Administrator kann in regelmäßigen Abständen die Mailfilt.hst aufräumen. Die automatisch eingefügten Einträge stehen ganz oben. Dadurch werden sie erstens zuerst abgearbeitet, und zweitens sind sie leicht aufzufinden. Zum Löschen gibt der Kommentar hinter den Einträgen Zeitpunkt und Quelle an.


 Das ist eine spezielle Anwendung dieses Prinzips. Es läßt sich darauf viel aufbauen. Für jeden Zweck kann es ein eigenes Postfach geben, oder mehrere Scripte bearbeiten den gleichen Account. Dann müssen sie darauf achten, an welche Adresse der Auftrag ging, und nur die für das jeweilige Script bestimmten Mails bearbeiten.

 Eine aktuelle Anwendung dieses Prinzips könnte die Moderation ;-) einer Gruppe sein. Der Moderator entscheidet, daß das eingereichte Posting (kam per Mail) veröffentlicht werden sollte. Diese Mail wird komplett, d.h. Raw und inkl. der Header per Mail an einen speziellen Account weitergeleitet (Forward unquoted). Das Script entfernt die Header der internen Mail, und optional noch Einiges, das nicht usenettypisch ist (Policy). Danach kommen Approved: und Sender: hinzu, wiederum optional eine PGP-Signatur. Das Ergebnis wird im News.Out abgelegt.