Skip to content

Commit

Permalink
Improvements to SpamAssassin plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
smfreegard committed May 9, 2012
1 parent 9b32ae4 commit 1701e74
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 15 deletions.
6 changes: 6 additions & 0 deletions contrib/Haraka.cf
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
loadplugin Mail::SpamAssassin::Plugin::Haraka Haraka.pm

ifplugin Mail::SpamAssassin::Plugin::Haraka
header __HARAKA eval:get_haraka_uuid()
endif

35 changes: 35 additions & 0 deletions contrib/Haraka.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package Mail::SpamAssassin::Plugin::Haraka;
my $VERSION = 0.1;

use warnings;
use strict;
use Mail::SpamAssassin::Plugin;
use vars qw(@ISA);
@ISA = qw(Mail::SpamAssassin::Plugin);

sub dbg {
Mail::SpamAssassin::Plugin::dbg ("Haraka: @_");
}

sub new {
my ($class, $mailsa) = @_;
$class = ref($class) || $class;
my $self = $class->SUPER::new($mailsa);
bless ($self, $class);
$self->register_eval_rule("get_haraka_uuid");
}

sub get_haraka_uuid {
my ($self, $pms) = @_;

# Add last external IP
my $le = $pms->get_tag('LASTEXTERNALIP');
if(defined($le) && $le) {
$pms->set_spamd_result_item( sub { return "last-external=$le"; } );
}
my $header = $pms->get("X-Haraka-UUID");
if(defined($header) && $header) {
$pms->set_spamd_result_item( sub { return "haraka-uuid=$header"; } );
}
return 0;
}
File renamed without changes.
73 changes: 72 additions & 1 deletion docs/plugins/spamassassin.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,76 @@
spamassassin
============

This plugin runs the mail through SpamAssassin.
This plugin implements the spamd protocol and will send messages to
spamd for scoring.

Configuration
-------------

spamassassin.ini

- spamd_socket = \[host:port | /path/to/socket\] *optional*

Default: localhost:783
Host or path to socket where spamd is running.

- spamd_user = \[user\] *optional*

Default: default
Username to pass to spamd. This is useful when you are running
spamd with virtual users.

You can also pass this value in dynamically by setting:

connection.transaction.notes.spamd_user

- max_size = N *optional*

Default: 500000
Maximum size of messages (in bytes) to send to spamd.
Messages over this size will be skipped.

- reject_thresold = N *optional*

Default: none (do not reject any mail)
SpamAssassin score at which the mail should be rejected.

- relay_reject_threshold = N *optional*

Default: none
As above, except this threshold only applies to connections
that are relays (e.g. AUTH) where connection.relaying = true.
This is used to set a *lower* thresold at which to reject mail
from these hosts to prevent sending outbound spam.

If this is not set, then the `reject_thresold` value is used.

- munge_subject_threshold = N *optional*

Default: none (do not munge the subject)
Score at which the subject should be munged (prefixed).

- subject_prefix = \[prefix\] *optional*

Default: *** SPAM ***
Prefix to use when munging the subject.

- old_headers_action = \[rename | drop | keep\] *optional*

Default: rename
If old X-Spam-* headers are in the email, what do we do with them?
`rename` them to X-Old-Spam-*.
`drop` will delete them.
`keep` will keep them (new X-Spam-* headers appear lower down in
the headers then).


Extras
======

A SpamAssassin plugin can be found in the `contrib` directory.
Haraka.\[pm|cf\] should be placed in the SpamAssassin local site rules
directory (/etc/mail/spamassassin on Linux), spamd should be restarted
and the plugin will make spamd output the Haraka UUID as part of it's
log output to aid debugging when searching the mail logs.

43 changes: 29 additions & 14 deletions plugins/spamassassin.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
// Valid keys:
// reject_threshold=N - score at which to reject the mail
// Default: don't reject mail
// relay_reject_threshold=N - score at which to reject mail from
// relays (to prevent outbound spam)
// Default: don't reject mail
// munge_subject_threshold=N - score at which to munge the subject
// Default: don't munge the subject
// subject_prefix=str - prefix to use when munging the subject.
Expand Down Expand Up @@ -39,7 +42,8 @@ exports.hook_data_post = function (next, connection) {
config.main[key] = config.main[key] || defaults[key];
}

['reject_threshold', 'munge_subject_threshold', 'max_size'].forEach(
['reject_threshold', 'relay_reject_threshold',
'munge_subject_threshold', 'max_size'].forEach(
function (item) {
if (config.main[item]) {
config.main[item] = new Number(config.main[item]);
Expand All @@ -64,8 +68,8 @@ exports.hook_data_post = function (next, connection) {
socket.setTimeout(300 * 1000);

var username = config.main.spamd_user ||
connection.transaction.notes.spamd_user ||
process.getuid();
connection.transaction.notes.spamd_user ||
'default';

var data_marker = 0;
var in_data = false;
Expand Down Expand Up @@ -109,10 +113,12 @@ exports.hook_data_post = function (next, connection) {
socket.write("SYMBOLS SPAMC/1.3\r\n", function () {
socket.write("User: " + username + "\r\n\r\n", function () {
socket.write("X-Envelope-From: " +
connection.transaction.mail_from.address()
+ "\r\n", function ()
{
send_data();
connection.transaction.mail_from.address()
+ "\r\n", function () {
socket.write("X-Haraka-UUID: " +
connection.transaction.uuid + "\r\n", function () {
send_data();
});
});
});
});
Expand Down Expand Up @@ -153,8 +159,10 @@ exports.hook_data_post = function (next, connection) {

plugin.fixup_old_headers(config.main.old_headers_action, connection.transaction);

if (spamd_response.flag === 'Yes') {
if (spamd_response.flag === 'Yes') {
connection.transaction.add_header('X-Spam-Flag', 'YES');
connection.transaction.remove_header('precedence');
connection.transaction.add_header('Precedence', 'junk');
}
connection.transaction.add_header('X-Spam-Status', spamd_response.flag +
', hits=' + spamd_response.hits + ' required=' + spamd_response.reqd +
Expand All @@ -169,17 +177,24 @@ exports.hook_data_post = function (next, connection) {
}
connection.transaction.add_header('X-Spam-Level', stars_string);

connection.loginfo(plugin, "spamassassin returned: " + spamd_response.flag + ', ' +
spamd_response.hits + '/' + spamd_response.reqd +
" Reject at: " + config.main.reject_threshold);
connection.loginfo(plugin, "status=" + spamd_response.flag + ', hits=' +
spamd_response.hits + ', required=' + spamd_response.reqd +
", reject=" + ((connection.relaying) ? (config.main.relay_reject_threshold || config.main.reject_threshold) :
config.main.reject_threshold) +
", tests=\"" + spamd_response.tests + "\"");

if (config.main.reject_threshold && (spamd_response.hits >= config.main.reject_threshold)) {
if ((connection.relaying && config.main.relay_reject_threshold && (spamd_response.hits >= config.main.relay_reject_threshold))
|| (config.main.reject_threshold && (spamd_response.hits >= config.main.reject_threshold))) {
return next(DENY, "spam score exceeded threshold");
}
else if (config.main.munge_subject_threshold && (spamd_response.hits >= config.main.munge_subject_threshold)) {
var subj = connection.transaction.header.get('Subject');
connection.transaction.remove_header('Subject');
connection.transaction.add_header('Subject', config.main.subject_prefix + " " + subj);
// Try and prevent any double subject modifications
var subject_re = new RegExp('^' + config.main.subject_prefix);
if (!subject_re.test(subj)) {
connection.transaction.remove_header('Subject');
connection.transaction.add_header('Subject', config.main.subject_prefix + " " + subj);
}
}
next();
});
Expand Down

0 comments on commit 1701e74

Please sign in to comment.