gertvdijk / purepythonmilter

Pure Python-asyncio Milter framework
Other
14 stars 1 forks source link

What is the correct way to set incoming mail to quarantine? #18

Open mkurkela opened 6 months ago

mkurkela commented 6 months ago

I was trying set some some incoming emails to quarantine

As the Quarantine class did not have encode method, I tried to do my own class derived from Quarantine class that defines the encode method.

class MyQuarantine(ppm.Quarantine):
  def encode(self) -> Payload:
    return Payload(self.response_char)
...

...
async def on_end_of_message(cmd: ppm.EndOfMessage) -> ppm.VerdictOrContinue:

  if quarantine.get():
    return MyQuarantine(); 

  return ppm.Continue()

I can successfully reject the message by replacing the return MyQuarantine() line with return ppm.RejectWithCode(primary_code=(5, 7, 1), text="Blocked address")

mkurkela commented 6 months ago

After some try & error and sendmail manual reading I managed to put the mail in hold queue

class MailQuarantine(AbstractManipulation):
  response_char: ClassVar[bytes] = b"q"  # SMFIR_QUARANTINE
  reason: str = "Quarantine this"
  def encode(self) -> Payload:
    return Payload(self.response_char + self.reason.encode() + b"\x00")
...
...
async def on_end_of_message(cmd: ppm.EndOfMessage) -> ppm.VerdictOrContinue:

  if quarantee.get():
    return ppm.Continue(manipulations=[MailQuarantine()])

  return ppm.Continue()
duobradovic commented 6 months ago

So it appears MTA (Postfix) is waiting for a Continue after SMFIR_QUARANTINE response.

buanzo commented 4 months ago

That is indeed the case. I had tried all combinations, until finally I checked opendmarc's source code and noticed QUARANTINE then ACCEPT or CONTINUE was the appropriate method. For python version reasons, I had to use pymilter instead of purepythonmilter which was my #1 choice so, just in case someone is in a similar situation: https://github.com/sdgathman/pymilter/issues/63#issuecomment-2159743336 - Cheers!