chapps.outbound module


And possibly other classes related to outbound traffic, but right now there is only one, which is an outbound-only subclass of chapps.util.PostfixPolicyRequest.

class chapps.outbound.OutboundPPR[source]

Bases: chapps.util.PostfixPolicyRequest

Encapsulates logic to identify the authenticated user sending the email.

Ignoring non-authenticated email attempts, which I think everyone does today, outbound requests should all be associated to a known user who has authenticated to Postfix. Postfix provides information in the payload which can be used to identify the user. That piece of data may then be used to apply policies to the outbound email of a particular user.

In order to allow for the possibility that other sites might prefer to use arbitrary bits of the Postfix policy request payload to identify users, CHAPPS allows for the key used to extract that data to be specified in the config file. At present, there is no support for combining more than one key.

Notes about subclassing

Don’t forget that the normal attribute space is reserved for the payload data. All internal attributes should start with _ (underscore).

__init__(payload, *, cfg=None)[source]

Create a new outbound policy request

classmethod clear_memoized_routines()[source]

Clear all memoized routines

This mainly exists to facilitate testing.

property user

Return and memoize the user-identifier.


the user-identifier

Return type


  • AuthenticationFailureException – when no user-identifier can be found, and the require_user_key setting of the [CHAPPS] section of the config is set to True

  • ValueError – when no user-identifier is found, but user keys are not required

The underlying routine raises ValueError when no user-identifier can be found. If the config stipulates that a user-identifier must be found, this routine raises AuthenticationFailureException to signal that the email originated from a source which did not authenticate.


Obtain the user value, and memoize the procedure

In an attempt to support as many different configuration scenarios as possible, the codebase can attempt to find a user-identifier in a few different places, in a search path. Since it is possible to configure this search path via the config file, the actual search function is produced as a closure and memoized at the class level, so that all future instances will be able to use the same function without creating a new (identical) closure first.

The closure produced by this factory raises ValueError if it cannot find a non-nil user-identifier.


Any alternate closure provided for this purpose should also raise ValueError if no user-identifier can be found, as it is handled explicitly in user()