zone-eu / zone-mta

📤 Modern outbound MTA cross platform and extendable server application
European Union Public License 1.2
599 stars 96 forks source link

How to push message in a hold queue #287

Closed matteomattei closed 2 years ago

matteomattei commented 2 years ago

Hello, is there a possibility, eventually with a plugin, to enqueue some messages (filtered by some logics) in an "hold" queue? I would like to push messages in a hold queue which is never dequeued and, only when I decide to unlock, move them to the active queue so that they can be delivered. Something like the Postfix "hold queue".

I saw the deferred functionality but I don't want to change the message date and I want to have control on when the messages are removed from the hold queue and added to the active queue.

andris9 commented 2 years ago

There is no such feature but you can emulate it by changing the assigned value of the queue record to a non-existing one, eg. like this:

db.collection('zone-queue').updateOne(
    { id: queueId, seq: seqId },
    {
        $set: {
            assigned: 'paused'
        }
    }
));

as there is no ZoneMTA instance with instanceId "paused", then no server picks that message up for delivery. Later when you want to un-pause, you can change the assigned value back to "no", so any instance could send it out.

matteomattei commented 2 years ago

Hi @andris9 and thanks for the info. Can you point me to the right hook that I can attach to write such plugin?

I looked at queue:route but it reports only the envelope and routing information which does not contain the queueId and the seqId needed to filter the result and apply the change to the assigned field.

What I am trying to implement is a mechanism to allow a user to deliver messages until a threshold is reached (for example 100 messages per day), after that, if a user exceed that threshold, all further message will be accepted by the MTA but kept in a paused queue until I decide to release (and so move them in the zone-queue for delivery) or reject (and delete) them.

andris9 commented 2 years ago

Well, yeah, it seems you can't do this like this as the assigned field is set immediately before storing the entry to the queue.

What you can do, though in the queue:route hook, is to provide a non-existing deliveryZone

app.addHook('queue:route', async (envelope, routing) => {
    routing.deliveryZone = 'paused';
});

If there is no such zone defined as "paused" then this message is never processed. I think it gets garbage collected after a while (maybe a week? have to check), so you can't keep it there indefinitely. If you want to "release " it, you have to manually update the database entry and set it to some existing zone id (eg. "default")

matteomattei commented 2 years ago

Great, it works fine! Just a question, if I decide to remove all stored messages which are in the "paused" queue, is it enough to remove them manually from mongodb (mail.chunks, mail.files and zone-queue) or is there any other thing to do? Or better, is there a cleaner way to purge a message?

dazoot commented 2 years ago

I think it's enough to remove them from zone-queue collection and there is a garbage collecting query in zone-mta which clean the chunks afterwards.

@matteomattei don't let the issue hang on if solved.

matteomattei commented 2 years ago

OK thank you