I spent a few hours working on a script that integrates hMailServer with SpamAssassin the "classic" way (via an OnDeliverMessage script). Some parts of this script were collected from posts all over this board, but others are new so I thought I would share it.
The script offers the following features:
- Create a log file so you can trace what's going on in the script.
- Suppress calling SpamAssassin if the mail was sent from your domain (either internally or outgoing).
- Provide an easy way to learn new spam with pretty much any mail client (tested with Thunderbird).
- Send confirmation mail when new spam was learnt.
As you can see, the first few lines provide an easy way to configure the script to do what you want. I have Spamassassin installed by "itself", i.e. not the spamd as a service (I read somewhere that this might not work on Win32, but this could be outdated information) but as a perl script.
Code: Select all
Sub OnDeliverMessage(oMessage) fname = oMessage.filename Dim debug Dim debugfile Dim hdebugfile, hlearnedfile Dim s1, SearchString Dim infile, testfile Dim fso Dim cmd, rc, sh Dim replyMail Dim spamLearnAddress Dim learnDirectory Dim learnSendConfirmationMail Dim learnSendConfirmationMailAddress 'CONFIGURATION 'debug: Determines whether a log file should be written debug = true 'debugfile: Name and path to the logfile debugfile = "C:\spam\log\debug.txt" 'spamLearnAddress: The address any unrecognized spam mail should be forwarded to as attachment, so it can be learned spamLearnAddress = "spam@<yourdomain>" 'learnDirectory: The directory where the attachments are saved to and sa-learn is called for. This directory must exist and contain a subdirectory called "log". 'learnDirectory should end with a backslash. learnDirectory = "C:\spam\" 'learnSendConfirmationMail: Determines whether an email with the result of sa-learn is sent or not. learnSendConfirmationMail = true 'SearchString: This is the string which when found signals that it is an outgoing message and therefore does not need to be scanned. SearchString = "from [10.0.1." 'CREATE/SET SOME COMMONLY USED VARIABLES/OBJECTS Set fso = createobject("Scripting.FileSystemObject") If Not fso.fileexists(fname) then result.Value = 0 Exit sub End If If debug = true then Set hdebugfile = fso.OpenTextFile(debugfile, 8, true, 0) hdebugfile.WriteLine ("--- Start OnDeliverMessage ---") End If infile = fso.getabsolutepathname(fname) testfile = infile & ".tmp" Set sh = CreateObject("WScript.Shell") 'LEARN MAILS SENT TO THE CONFIGURED SPAM LEARN ADDRESS AS SPAM IF ANY ATTACHMENT IS FOUND if oMessage.Attachments.Count > 0 then if debug = true then hdebugfile.WriteLine ("Checking whether spamassassin should learn this message as spam") end if for iRecipient = 0 to oMessage.Recipients.Count-1 if debug = true then hdebugfile.WriteLine ("Recipient: " & oMessage.Recipients(iRecipient).Address) end if if oMessage.Recipients(iRecipient).Address = spamLearnAddress then 'save all attachments to disk and execute sa-learn if debug = true then hdebugfile.WriteLine ("This message was sent to the configured spam learn address " & spamLearnAddress) end if for iAttachment = 0 to oMessage.Attachments.Count-1 oMessage.Attachments(iAttachment).SaveAs(learnDirectory & iAttachment & ".eml") next cmd = "cmd /c sa-learn --spam " & learnDirectory & " > " & learnDirectory & "log\learned.txt" rc = sh.Run(cmd, 0, true) for iAttachment = 0 to oMessage.Attachments.Count-1 fso.DeleteFile (learnDirectory & iAttachment & ".eml") next if debug = true or learnSendConfirmationMail = true then ' Read the sa-learn result Set hlearnedfile = fso.OpenTextFile(learnDirectory & "log\learned.txt", 1, true, 0) learnedResult = hlearnedfile.ReadLine hlearnedfile.Close Set hlearnedfile = Nothing if learnSendConfirmationMail = true then Set replyMail = CreateObject ("hMailServer.Message") replyMail.From = "hMailServer" replyMail.FromAddress = oMessage.FromAddress replyMail.Subject = "Learned SPAM" replyMail.AddRecipient "Admin", oMessage.FromAddress replyMail.Body = learnedResult replyMail.Save Set replyMail = Nothing end if end if ' Reject mail and terminate result.Value = 1 if debug = true then hdebugfile.WriteLine ("Result from sa-learn: " & learnedResult) hdebugfile.WriteLine ("--- End OnDeliverMessage ---") hdebugfile.Close Set hdebugfile = Nothing end if Set fso = Nothing Set sh = Nothing Exit Sub end if next else if debug = true then hdebugfile.WriteLine ("No attachment found - spam learn check skipped.") end if end if 'SKIP SPAM CHECKS ON OUTGOING MAIL if debug = true then hdebugfile.WriteLine ("Check whether this is an outgoing mail") end if s1 = oMessage.HeaderValue("Received") If InStr(1, s1, SearchString, 1) > 0 Then if debug = true then hdebugfile.WriteLine ("Message was sent from local domain. Skipping spam check.") end if 'Comment out the next two lines if you don't want a header created oMessage.HeaderValue("X-SpamCheck-Status") = "Spam checks skipped on mail sent from local domain" oMessage.Save() if debug = true then hdebugfile.WriteLine ("--- End OnDeliverMessage ---") hdebugfile.Close Set hdebugfile = Nothing end if Set fso = Nothing Set sh = Nothing Exit Sub End If 'CALL SPAMASSASSIN (modify as required) if debug = true then hdebugfile.WriteLine ("Calling SpamAssassin for this message") end if 'Copy file into a testfile fso.CopyFile infile, testfile if debug = true then hdebugfile.WriteLine ("File copied to " & testfile) end if cmd = "cmd /c perl -S -T -w spamassassin < """ & testfile & """ > """ & infile & """" rc = sh.Run( cmd , 0 , TRUE) If rc = 0 Then 'Do something for HAM if debug = true then hdebugfile.WriteLine ("Message is HAM.") end if ElseIf rc = 1 Then 'Do something for SPAM if debug = true then hdebugfile.WriteLine ("Message is SPAM.") end if 'Uncomment next two lines to reject spam ' result.Value = 1 ' Exit Sub End If If fso.GetFile(infile).Size = 0 Then 'Failsafe: In the event an error causes a zero byte msg fso.CopyFile testfile, infile End if fso.Deletefile testfile Set fso = Nothing Set sh = Nothing if debug = true then hdebugfile.WriteLine ("--- End OnDeliverMessage ---") hdebugfile.Close Set hdebugfile = Nothing end if result.value = 0 End Sub
If your users want to submit new spam mails to be learnt, they forward the unrecognized spam mail as an attachment to the address specified in spamLearnAddress. They can attach multiple spam mails as attachments. It is necessary to forward them as attachment because otherwise the sender will be their own account, and spamassassin might learn their address to be a spammer's address (actually, the script will skip learning if it doesn't find any attachments).
If learnSendConfirmationMail is set to true, the user submitting a new mail that should be learned will receive an email with the result of sa-learn.
Maybe this helps someone - it seems to be working okay on my machine. If you find this useful or have questions, let me know