• If you are still using CentOS 7.9, it's time to convert to Alma 8 with the free centos2alma tool by Plesk or Plesk Migrator. Please let us know your experiences or concerns in this thread:
    CentOS2Alma discussion

Resolved Mail-Handler - REJECT with message?

lippoliv

Basic Pleskian
Hey there,
I did register an Mail-Handler (had a view discussions about that here https://talk.plesk.com/threads/extension-dev-handling-mails.338811/) and today morning I played with the "PASS" and "REJECT" output.

Quickly an question raises: How can I pass a custom Message for the reasen about REJECT the mail into the "Undelivered Mail Returned to Sender" Mail?
Currently there's just the standard header and the text "Message can't be delivered".

I tryed the "LOG" but that is just logging, the message dont appear in the mail.

Code:
echo "REJECT" >&2
echo "$originalmail"
exit 0

Would be nice to add a message to "REJECT" like it is possible with LOG
Code:
# LOG reject reason
echo "LOG Your spamming to much messages within a timerange of 5 Minutes"

# Write REJECT and reason
echo "REJECT Your spamming to much messages within a timerange of 5 Minutes"

Or am I missing the right way to do so?
 
Here's a python code snippet to reject with a custom message:

Code:
class MailHandler(object):
    HOOK_REJECT  = 3

    def exit_reject(self):
        sys.stderr.write("REJECT")
        sys.exit(self.HOOK_REJECT)

    def data(self, msg):
        sys.stderr.write("DATA %s\n" % msg)

    def reply(self, rcode, xcode, message):
        if not rcode and xcode:
            raise ValueError("rcode should not be empty when xcode is specified")
        r = "REPLY"
        if rcode:
            r += ":" + rcode
        if xcode:
            r += ":" + xcode
        r += " " + message
        self.data(r)

    def reject_with_custom_message(self):
        self.reply("554", "5.7.0", "Your message could not be sent. This is a custom message.")
        self.exit_reject()

Hope it's enough to get you started.
 
As of I have an Shell-Script I can't use your Code. But I had a look on it and I think that should be possible via Shell too, but I don't get it up.

Here's the Shell Code:

Code:
echo "DATA REPLY: 554: 5.7.1 My Message" >&2
echo "REJECT" >&2

echo "$msg"

exit 0

An this is the Output

Code:
Oct 22 10:41:13 v22016081573736335 /usr/lib/plesk-9.0/psa-pc-remote[17598]: handlers_stderr: DATA REPLY: 554: 5.7.1 My Message#012REJECT
Oct 22 10:41:13 v22016081573736335 /usr/lib/plesk-9.0/psa-pc-remote[17598]: REJECT during call 'LWAutomail' handler
Oct 22 10:41:13 v22016081573736335 /usr/lib/plesk-9.0/psa-pc-remote[17598]: SMTP reply code was not specified by handler
Oct 22 10:41:13 v22016081573736335 postfix/cleanup[12135]: B971DFF81B: milter-reject: END-OF-MESSAGE from mail.w4.lipperts-web.de[212.83.34.226]: 4.7.1 Service unavailable - try again later; from=<[email protected]> to=<[email protected]> proto=ESMTP helo=<w4.lipperts-web.de>

I dont get any Reply from mailer-daemon at this Point.

While removing the "DATA" from the first echo i get an Response:

Code:
echo "REPLY: 554: 5.7.1 My Message" >&2
echo "REJECT" >&2

echo "$msg"

exit 0

Code:
Oct 22 10:42:44 v22016081573736335 /usr/lib/plesk-9.0/psa-pc-remote[17598]: handlers_stderr: REPLY: 554: 5.7.1 My Message#012REJECT
Oct 22 10:42:44 v22016081573736335 /usr/lib/plesk-9.0/psa-pc-remote[17598]: REJECT during call 'LWAutomail' handler
Oct 22 10:42:44 v22016081573736335 postfix/cleanup[12135]: 8FC2AFF81B: milter-reject: END-OF-MESSAGE from mail.w4.lipperts-web.de[212.83.34.226]: 5.7.1 Command rejected; from=<[email protected]> to=<[email protected]> proto=ESMTP helo=<w4.lipperts-web.de>

Code:
<[email protected]>: host
    v22016081573736335.megasrv.de[46.38.233.156] said: 550 5.7.1 Command
    rejected (in reply to end of DATA command)

As you can see ist not "554" and not my message.
I tryed various ideas, but got nothing running.

Is this may just possible with an python-script?
 
It would be really nice if I could finish my implementation. Some help from Plesk team would be great.
 
@lippoliv, with a little bit of effort it's fairly easy to adapt the provided snippet in Python to any other language. What's important here is the attention to details.

Here's an example how to add a Bash script as a custom mail handler to reject all mails received by a specific mail address via SMTP with a custom error code and message.

Code:
root@a10-52-38-93:~# cat /opt/psa/handlers/hooks/reject-reply
#!/bin/bash

data()
{
        echo "DATA $*" >&2
}

reply()
{
        local rcode="$1"
        local xcode="$2"
        local message="$3"

        data "REPLY${rcode:+:$rcode}${xcode:+:$xcode} $message"
}

reject()
{
        echo "REJECT" >&2
        exit 3
}

reply 554 5.7.1 "My message"
reject
root@a10-52-38-93:~# ls -l /opt/psa/handlers/hooks/reject-reply                                                                   
-rwxr-x--- 1 root popuser 249 Nov 11 10:39 /opt/psa/handlers/hooks/reject-reply
root@a10-52-38-93:~# plesk sbin mail_handlers_control --add --priority 5 --name reject-msg --mailname [email protected] --queue before-queue --type recipient --executable /opt/psa/handlers/hooks/reject-reply --dont-preserve-on-restore --enabled
root@a10-52-38-93:~# plesk sbin mail_handlers_control --list
.---.---.-------.--------------------------------------.-----------------.------------------.-----------------.
| E | P | prior |               address                |       name      |       type       |      queue      |
|---|---|-------|--------------------------------------|-----------------|------------------|-----------------|
|   |   |    10 |                                  all |             spf |           global |    before-queue |
| X |   |    10 |                       all-recipients |     check-quota |           global |    before-queue |
| X |   |    10 |                       all-recipients |     check-quota |           global | before-sendmail |
| X |   |    20 | [email protected] |           drweb |           sender |   before-remote |
| X |   |    20 | [email protected] |           drweb |        recipient |    before-queue |
| X |   |     5 | [email protected] |      reject-msg |        recipient |    before-queue |
'---'---'-------'--------------------------------------'-----------------'------------------'-----------------'
root@a10-52-38-93:~# /opt/psa/handlers/hooks/reject-reply
DATA REPLY:554:5.7.1 My message
REJECT
root@a10-52-38-93:~# echo $?
3
root@a10-52-38-93:~# telnet localhost smtp
Trying ::1...
Connected to localhost.
Escape character is '^]'.
220 a10-52-38-93.qa.plesk.ru ESMTP Postfix (Debian/GNU)
EHLO localhost
250-a10-52-38-93.qa.plesk.ru
250-PIPELINING
250-SIZE 10240000
250-ETRN
250-STARTTLS
250-AUTH DIGEST-MD5 CRAM-MD5 PLAIN LOGIN
250-XFORWARD NAME ADDR PROTO HELO SOURCE PORT IDENT
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN
MAIL FROM: [email protected]
250 2.1.0 Ok
RCPT TO: [email protected]
250 2.1.5 Ok
DATA
354 End data with <CR><LF>.<CR><LF>
To: [email protected]
Subject: Test

this is a test message
.
554 5.7.1 My message
QUIT
221 2.0.0 Bye
Connection closed by foreign host.
root@a10-52-38-93:~#

You probably wouldn't want to use --dont-preserve-on-restore above (I used it because I don't care whether this test handler persists over mail restore). Everything else should be fairly close to what you want.
 
Last edited:
Is it possible, that the reply is to late in "before-local". It work's in "before-remote" but not in "before-local".
In both ways the mail got rejected, but my custom message just via rejecting in "before-remote"
 
OK now I'm done I think. But I had to work way other than I thought it would work.

I used "before-remote" for outgoing Mails, and "before-local" for incoming. Then I mentioned, "before-remote" is called on both (Name is confusing then).
So I used local IPs the the IP of the senders Domain to figure out if its an incomming or outgoing mail. Worked.
I still had to use "before-local" because just in this Queue I have the spam-check informations.

But on "before-local" I just could reject, my custom message won't be give out to the Sender.

Now I changed my whole Idea. More Tasks to my script, but maybe with an small benefit for me:

I just act on "before-remote". I ran SpamAssassin manually to the mail I want to check, as of the headers aren't available in this Point. This takes one or two seconds but it should be OK as the Server load is small.

Benefit: Also for outgoing mails, my SpamAssassin is run and has checked the mail with the same rules as he will do for incomming mails.
And I'am able to reject with my custom message.
 
Is it possible, that the reply is to late in "before-local". It work's in "before-remote" but not in "before-local".

Yes, in before-local it's too late, since it is executed in the MDA (mail delivery agent) context. Handler needs to be executed in SMTP (or to lesser extent, sendmail) context for REPLY to have any effect.

I ran SpamAssassin manually to the mail I want to check

There's a SpamAssassin integration in Plesk. Doesn't it suit your needs?
 
Back
Top