On 2003-12-19 10:28:29 -0700, Bryan Scott wrote:
> Hey all,
> 
> >I have done something similar for my "aliases" plugin. It allows to
> >specify per recipient options like this:
> >
> >[EMAIL PROTECTED]: [EMAIL PROTECTED] (denysoft_greylist, 
> >spamassassin_reject_threshold=10)
> >
> >This would set a transaction note with key "recipient_options" and the
> >value { denysoft_greylist => 1, spamassassin_reject_threshold => 10 },
> >which other plugins can then access. 
> [...snip..]
> >I would appreciate it if others would use the same scheme, and I am
> >open to suggestions for improvement (I see a bit of danger in qpsmtpd
> >that everybody does it his own way).
> 
> Is the information stored in a database (mysql) or a flat file/dbm 
> format? 

Flat file. Parsing a file of 2000 lines takes about 0.08 seconds on our
mail server, and it gets only 5000 mails per day, so I wasn't very
motivated to improve the scalability.

> I would like to be able to integrate it into vpopmail's 
> database somehow, although putting it into its own file would be 
> supportive of more implementations.

In the aliases plugin, the per recipient options are more an
afterthought. The main purpose of the plugin is, to determine which
local addresses exist and to expand aliases. I realize that there are
several such plugins out there and I think this is a good thing, because
everybody can use their existing user databases (whether thats flat
files, DBM, CDB, LDAP, an RDBMS, ...).

What I would like, though, is to specify a common mechanism to pass such
information from one module to another. I had to modify
denysoft_greylist to get it do what I needed and Gavin didn't accept my
patches because in the mean time he had implemented a different
mechanism. So now there are two slightly different versions of the
denysoft_greylist module, and that is a bad thing, IMHO. 

This is why I think that we need a standard way to access per-recipient
configurations. Then we can have a number of modules which get the
configuration from a file, a database, or whatever, and other modules
can access the configuration without having to bother how it is
retrieved.

The core of my proposal is really just this:

* There is a well-known transaction note "recipient_options", which is a
  hash. This note contains options for a single recipient and should
  only be used in methods called from the "rcpt" hook.

* Plugins which want to base decisions on recipient options, look up
  keys in this hash. The names of the keys and the semantics of the
  values are defined by the plugin.

* The hash is populated by one or more plugins which are called early in
  the rcpt hook. How they do that is completely up to them.

That's it. Simple, eh?

However, a number of conventions can be built around it:

* The first (or last) plugin in the rcpt hook should clear the note
  to avoid accidental mixing of options intended for different
  recipients.

* Each plugin should have a defined namespace. Possible choices:

    * Each plugin owns all keys starting with the name of the plugin.

    * Each plugin owns exactly the key which is its own name. All
      options must be stored in a hash below that key.

* If a plugin needs recipient-specific options at a later point (e.g.
  in the data_post hook), it can just copy them to a plugin-specific
  note in the rcpt hook and access them later.

> Looks like the transaction note works with the API idea that Ask had, 

Has Ask said anything more about his idea other than that he had one? If
so I must have missed it. Pointers?

> although I think that we might want a rcpt_preferences thingy separate 
> from transaction notes, as we're looking at the potential of more than 
> one recipient (as Matt suggested).

Right. I solved (or sidestepped) the issue by limiting the lifetime of
the note to the rcpt hook for a single recipient. If a plugin needs the
configuration of several recipients, it has to save them itself. I think
this is appropriate since the meaning is plugin-dependent anyway.

> We might be blocking for one rcpt, 
> tagging for another, and receiving (but not queueing) for the third. (Is 
> all that even possible in a transaction?)

Depends on where in the transaction the decisions happen. For each RCPT
TO, you can individually return success or failure. However, for DATA,
there is only one return code. So for example, the spamassassin module
it is not possible to reject the message for one recipient, but to
accept it for another. (LMTP changes that, but its use is discouraged on
the internet)


> So this:
> 
> >    {
> >     dnsbl => {
> >         'dnsbl.njabl.org' => 'block',
> >         'bl.spamcop.net' => 'tag'
> >     },
> >     spamassassin => {
> >         threshold => { tag => 5, reject => 10 }
> >     },
> >    }
> 
> might turn into something like this:
> 
> %rcpt_opts =  { '[EMAIL PROTECTED]' => {
>                       dnsbl => {
>                            'dnsbl.njabl.org' => 'block',
>                            'bl.spamcop.net' => 'tag'
>                        },
>                       spamassassin => {
>                            tag_threshold => 5,
>                            reject_threshold => 10,
>                            more_opts => go_here
>                       },
>                 },
>                 'bbsc.net' => {
>                       spamhelo => {
>                            myipaddress => 'block',
>                            dynamichost => 'tag'
>                       }
>                };

Actually, in my aliases plugin, the parser returns a hash very much like
that and stores it in plugin-local variable. Then in the rcpt hook, the
recipient is looked up and the options for that specific recipient are
stored in the transaction note. I consider that an implementation
detail, though. I could change that to skip the initial parsing of a
file and just do a database lookup in the rcpt hook, and the usage of
the module would be exactly the same.

> Which is the same as yours, but adds places for the users and wildcard 
> domains. I would think it easy to go a step further and merge users 
> under their parent domains.  Either way, parent domain rules would be 
> the default, with individual users' settings overriding domain defaults. 
> (Some of that could be determined during config file generation, 
> negating the need for loading generic defaults here.)

Dito. It is up to the module how it gets the values it puts into the
transaction note. If wants to fall back on default values for the domain
for values not set for a specific recipient, that's fine.

        hp

-- 
   _  | Peter J. Holzer    | In this vale
|_|_) | Sysadmin WSR       | Of toil and sin
| |   | [EMAIL PROTECTED]         | Your head grows bald
__/   | http://www.hjp.at/ | But not your chin.           -- Burma Shave

Attachment: pgp00000.pgp
Description: PGP signature

Reply via email to