Plugin API

Handy functions in the fuglu.shared module

fuglu.shared.actioncode_to_string(actioncode)

Return the human readable string for this code

fuglu.shared.string_to_actioncode(actionstring, config=None)

return the code for this action

fuglu.shared.apply_template(templatecontent, suspect, values=None, valuesfunction=None)

Replace templatecontent variables as defined in https://fumail.gitlab.io/fuglu/plugins-index.html#template-variables with actual values from suspect the calling function can pass additional values by passing a values dict

if valuesfunction is not none, it is called with the final dict with all built-in and passed values and allows further modifications, like SQL escaping etc

fuglu.shared.default_template_values(suspect, values=None)

Return a dict with default template variables applicable for this suspect if values is not none, fill the values dict instead of returning a new one

The Suspect class

class fuglu.shared.Suspect(from_address, recipients, tempfile, att_cachelimit=None, smtp_options=set([]))

The suspect represents the message to be scanned. Each scannerplugin will be presented with a suspect and may modify the tags or even the message content itself.

add_header(key, value, immediate=False)

adds a header to the message. by default, headers will added when re-injecting the message back to postfix if you set immediate=True the message source will be replaced immediately. Only set this to true if a header must be visible to later plugins (eg. for spamassassin rules), otherwise, leave as False which is faster.

added_headers = None

To keep track of already added headers (not in self.addheaders)

client_info_from_rcvd(ignoreregex=None, skip=0)

returns information about the client that submitted this message. (helo,ip,reversedns)

This information is extracted from the message Received: headers and therefore probably not 100% reliable all information is returned as-is, this means for example, that non-fcrdns client will show ‘unknown’ as reverse dns value.

if ignoreregex is not None, all results which match this regex in either helo,ip or reversedns will be ignored

By default, this method starts searching at the top Received Header. Set a higher skip value to start searching further down.

both these arguments can be used to filter received headers from local systems in order to get the information from a boundary MTA

returns None if the client info can not be found or if all applicable values are filtered by skip/ignoreregex

clientinfo = None

holds client info tuple: helo, ip, reversedns

debug(message)

Add a line to the debug log if debugging is enabled for this message

static decode_msg_header(header)

Decode message header from email.message into unicode string

Args:
header (str, email.header.Header):
Returns:
str
get_client_info(config=None)

returns information about the client that submitted this message. (helo,ip,reversedns)

In before-queue mode this info is extracted using the XFORWARD SMTP protocol extension.

In after-queue mode this information is extracted from the message Received: headers and therefore probably not 100% reliable all information is returned as-is, this means for example, that non-fcrdns client will show ‘unknown’ as reverse dns value.

if no config object is passed, the first parseable Received header is used. otherwise, the config is used to determine the correct boundary MTA (trustedhostregex / boundarydistance)

get_headers()

Returns the message headers as string

Returns:
(unicode str) unicode for Py2, str for Py3
get_message_rep()

returns the python email api representation of this suspect

get_original_source(maxbytes=None)

returns the original, unmodified message source

get_source(maxbytes=None)

returns the current message source, possibly changed by plugins

get_tag(key, defaultvalue=None)

returns the tag value. if the tag is not found, return defaultvalue instead (None if no defaultvalue passed)

is_blocked()

Returns True if ANY plugin tagged this suspect as blocked

is_ham()

Returns True if message is neither considered to be spam, virus or blocked

is_highspam()

Returns True if ANY of the spam engines tagged this suspect as high spam

is_modified()

returns true if the message source has been modified

is_spam()

Returns True if ANY of the spam engines tagged this suspect as spam

is_virus()

Returns True if ANY of the antivirus engines tagged this suspect as infected

modified_headers = None

To keep track of modified headers

static prepend_header_to_source(key, value, source)

Prepend a header to the message

Args:
key (str): the header key value (str): the header value source (bytes): the message source
Returns:
bytes: the new message buffer
set_header(key, value)

Replace existing header or create a new one

Args:
key (string): header key value (string): header value
set_message_rep(msgrep, att_mgr_reset=True)

replace the message content. this must be a standard python email representation Warning: setting the source via python email representation seems to break dkim signatures!

The attachment manager is build based on the python mail representation. If no message attachments or content is modified there is no need to recreate the attachment manager.

Args:
msgrep (email): standard python email representation
Keyword Args:
att_mgr_reset (bool): Reset the attachment manager
set_source(source, encoding='utf-8', att_mgr_reset=True)

Store message source. This might be modified by plugins later on…

Args:
source (bytes,str,unicode): new message source
Keyword Args:
encoding (str): encoding, default is utf-8 att_mgr_reset (bool): Reset the attachment manager
set_tag(key, value)

Set a new tag

source = None

holds the message source if set directly

to_address

Returns the first recipient address

to_domain

Returns the local part of the first recipient

to_localpart

Returns the local part of the first recipient

update_subject(subject_cb, **cb_params)

update/alter the message subject :param subject_cb: callback function that alters the subject. must accept a string and return a string :param cb_params: additional parameters to be passed to subject_cb :return: True if subject was altered, False otherwise

The SuspectFilter class

class fuglu.shared.SuspectFilter(filename)

Allows filtering Suspect based on header/tag/body regexes

file_changed()

Return True if the file has changed on disks since the last reload

get_args(suspect, extended=False)

returns all args of matched regexes in a list if extended=True: returns a list of tuples with all available information: (fieldname, matchedvalue, arg, regex)

get_decoded_textparts_deprecated(messagerep)

Returns a list of all text contents

get_field(suspect, headername)

return a list of mail header values or special values. If the value can not be found, an empty list is returned.

headers:
just the headername or header:<headername> for standard message headers mime:headername for attached mime part headers
envelope data:
envelope_from (or from_address) envelope_to (or to_address) from_domain to_domain clientip clienthostname (fcrdns or ‘unknown’) clienthelo
tags
@tagname
body source:
body:full -> (full source, encoded) body:stripped (or just ‘body’) : -> returns text/* bodyparts with tags and newlines stripped body:raw -> decoded raw message body parts
lint()

check file and print warnings to console. returns True if everything is ok, False otherwise

matches(suspect, extended=False)

returns (True,arg) if any regex matches, (False,None) otherwise

if extended=True, returns all available info about the match in a tuple: True, (fieldname, matchedvalue, arg, regex)

strip_text(content, remove_tags=None, replace_nbsp=True, use_bfs=True)

Strip HTML Tags from content, replace newline with space (like Spamassassin)

Returns:
(unicode/str) Unicode string (Py3 ‘str’ is unicode string)