Forum OpenACS Development: RFC: Callbacks for Incoming Emails

Collapse
Posted by Nima Mazloumi on
I would like to suggest a new architecture for incoming emails that allow packages to benefit from.

Currently we have two sweepers scanning for incoming emails:

- acs_mail_lite::scan_replies
- notification::email::scan_replies (only if EmailQmailQueueScanP set to 1 at server startup)

Looking at the code I realized that both sweepers contain in major parts the same or equivalent code.

Also if both sweepers are running the first one started as a scheduled proc will process all incoming emails and delete them before the other had a chance to process them as well.

In order to reduce redundancy I would like to suggest the removal of the notification sweeper in favour of that in acs-mail-lite and to extend acs-mail-lite with these procs:

1. acs_mail_lite::register_prefix -prefix -package-key
This procs stores prefixes packages are listen to in
the To-Address/Reply-to header of emails like

for acs_mail_lite: bounce
for notifications: notification

2. acs_mail_lite::unregister_prefix -package-key

Based on this acs-mail-lite will have an admin interface that allows the site user to activate/deactive package functionality for email processing.

3. acs_mail_lite::incoming_email callback
The interface all packages have to implement if interested in incoming emails

4. acs_mail_lite::incoming_email implementation for acs-mail-lite
The implementation for acs-mail-lite, basically what
the package does right now but migrated to use the
new callback functionality.

Notifications will be migrated to use the above as well by providing an implementation for acs_mail_lite::incoming_email.

Notification itself is used by several other packages. All emails sent out by notification have currently the Sender set to:

[reply_address_prefix]-$object_id-$type_id@[address_domain]

i.e.

mailto:notification-43432-43243@myhost.com

The type_id tells notifications which package has initiated the notification in the first place (i.e. forums) and the object_id tells the corresponding package for what object (i.e. message_id) the notifications was created for.

Now either notification has also to provide a callback interface like acs_mail_lite (a) which those packages have to implement who listen to replied notification emails or we extend notifications to accept an optional sender and/or reply-to header to be used (b).

(a) If the optional sender is passed this one is used in favour of the above since it could contain important information the corresponding package needs to process the reply. The package has then to register his prefix and implement the acs-mail-lite callback.

(b) Here, notifications will like acs-mail-lite provide a callback interface:

notifications::incoming_email callback

Any application that would like to process these emails will need to implement this callback.

Thus as soon as an email arrives acs-mail-lite will
check the prefix and call the correspondig implementation
of acs_mail_lite::incoming_email directly or in case of the notifications prefix notifications first which will forward the email to the corresponding package if it has implemented notifications::incoming_email.

The above solution would allow any package to process
incoming emails. A package would need to implement one or both of the below callbacks:

acs_mail_lite::incoming_email
notifications::incoming_email

The above solution would allow packages to listen to replies either from emails they have sent out directly or through notifications. In case of notifications the package has the choice to be content with what notifications stores in the to address (object_id) by implementing notifications::incoming_email or to pass itself a more package specific reply-to/sender header to be used and implementing acs_mail_lite::incoming_email instead.

Let me give an example with forums:

If someone has requested notifications for a subject he/she will receive lets say an email for a new messages posted and if she/he replies to the email a reply should be posted in this forums.

Now forums doesn't send out emails itself I rather creates a new notifications calling notification::new.

Forums could now call notification::new without the reply-to switch.

In this case forums need to implement notifications::incoming_email and use the object_id later on together with the repliers email address to verify the existenz of the replier, the forum and the write permissions.

Forums could instead pass a more sophisticated reply-to header

mailto:forums-$message_id-$user_id@myhost.com

And to do with it something more intelligent. In this case it would implement acs_mail_lite::incoming_email.

Any comments?

Collapse
Posted by Nima Mazloumi on
It would be nice if every package instance could define its own prefixes to listen to. Like what acs mail lite and notifications do now.

But if we allow that it would leed to the following problem:

- the parameter is set on the package instance level, how does acs mail lite find that out
- for each prefix an entry in /etc/postfix/virtual is required. Should acs mail lite be allowed to create these entries

Another question is if you have a single mail server but several oacs sites running, how do you make sure that the right site gets the email forwarded by postfix.

I personally would recommend not to do that on instance level. Instead since each package interested in processing incoming emails has to provide an implementation for the callback I would go for a standard rule. Any of these packages are required to send out the From or Reply-To header like this:

mailto:impl_name-whatever@myhost.com

So the sweeper in acs mail lite will extract the impl_name which is equal to the name of the callback implementation and and call the corresponding proc to process the email.

Also Dave recommended since you can have a single mail server multiple site instances scenario to go for something like this:

mailto:sitetoken-impl_name-whatever@myhost.com

For each sitetoken there is an entry in the postfix configuration. Thus postfix would forward always to the correct site instance.

Note: "whatever" is all that a package can define required to process the email correctly and is therefore package specific.

With this solution we wouldn't need packages to register/unregister prefixes.

Any comments?

Collapse
Posted by Peter Alberer on
I would propose to forget about exposing any system internals in the email adress. It is totally unnecessary and creates security risks. A user could (in the current implementation CAN) forge a forums post just by guessing an object_id and a user_id (both are easily found out).

So my proposal is to send all emails from an address like openacs-XXXXXXXXX. The XXX is a secret token that is generated individually for each mail sent out and is registered in the database together with all necessary info about the reply (object_id, notif_type_id, user_id, whatever). When a mail comes back we can look into the "incoming_mail_allowed_tokens" table and get all of the details to process the reply. (i have not thought about any details of this process, but using callbacks sounds good)

This way we do not have to care about modyfiying postfix files for every new package that wants to get incoming mail.

Collapse
Posted by Malte Sussdorff on
Peter, sadly this does not help with the following szenario: A company has a central email incoming folder for mails from customers. From there the email should be forwarded to a project in Project Manager to be stored there for reference with the project. As this is not a "reply to", you send a new message to the project. And you don't want the secretary to remember cryptic keys which she has to compute manually to send the mail, but use "p-$project_id@myserver" to send the mail to.

So I agree, if we have a "reply to", then we could circumwent this issue and also have additional security for e.g. forum postings, but this is not a general solution for the incoming e-mail challenge.

Collapse
Posted by Torben Brosten on
Can the service/package include 2 parameters?

1. switches on reply-to the way Peter describes, and

2. switches on accepting email that passes a filter that functions like a standard spam/forwarding filter

Collapse
Posted by Malte Sussdorff on
I'm not even sure we need to parameters. For reply-to's Peter's way works fine and should be walked. If a package additionally wants to provide a "send me email directly without hitting reply to" then it could offer this. It would have to be setup anyway in postfix, so having a parameter to turn it on/off IMO is not necessary (it is turned on when postfix is configured that way).