1

Trying to filter mails through a Sieve function.

I would like to fetch an e-mail address indicated inside the body of the message, and not in the header. This address is (like the one in the header) after a From: field. After that, a copy of the email should be sent to this address. Messages filtered must also have Returned mail inside their subject.

This is my code, but not working...

        require ["body","copy","variables"];

        if header :contains "Subject" "Returned mail"
            {
            if body :content "text" :matches "From: *"
                {
                redirect :copy "${1}";
                }
            }

Can you please help me to fix that code ? Thank's !!

Satch
  • 43
  • 8
  • Sadly this MUST NOT BE POSSIBLE by RFC 5173 Abs. 6. Wich annoyes me too. Maybe building a stupid workaround by piping the whole message to a python-script dedicated to the single match wich than returns the result via its return variable? Procmail ftw. – Sprinterfreak Nov 07 '17 at 02:10

2 Answers2

2

Switch back to good old procmail

Procmail does support matching within the message body like this:

:0H
* ^Subject: .*Returned mail
{
 :0B
 * ^From: \/.+@.+
 {
  ADDR=$MATCH
  :0 c
  * ADDR ?? ^[a-z0-9_-+.]+@[a-z0-9-+.]+$
  | $ADDR
 }
}

This covers everything after, in the line beginning with "From: ", in the message body.

:0B means the next matching has to be done on the message body

\/ in the expression starts the record to $MATCH (build-in variable)

The match is stored in the Procmail variable $ADDR wich then is permanently accessible within the furturer procmail script execution. In the subblock it delivers (:0 carbon copys) the message to the newly matched destination address. But note that at this point it is not safely checked if it really is an email address. This leaves also maybe a vulnurability for a remote code execution.

There MUST BE also any X-Loop protection techniq applied manually wich is not covered by this example

Sprinterfreak
  • 504
  • 4
  • 10
1

There is no way to grep things directly out of the message body for further processing. Sieve does not populate variables like ${1} from body matches.

The RFC states clearly that this MUST NOT be possible.

There is however a possibility to solve this issue by feeding (filtering) the message threw a seperate application like as follows wich puts the desired informations into the header.

Imagine the original message was:

To: my@second.tld
Subject: Test
From: other@example.tld
Date: Wed, 25 Oct 2017 16:22:05 +0200

Hi guy, here starts the body
This mail contains a important dynamic address

From: important@match.tld

wich has to be matched und processed by sieve

Then Your sieve could look like this:

require ["copy","variables","vnd.dovecot.filter"];

if header :contains "Subject" "Returned mail" {
    filter "bleed_from.py";
    if header :matches "Bleeded-From" "*" {
        redirect :copy "${1}";
    }
}

The filter-script "bleed_from.py":

#!/usr/bin/python
import re
import email

# Read the mail from stdin
parser = email.FeedParser.FeedParser()
mail = None
for line in sys.stdin.readlines():
    parser.feed(line)
mail = parser.close()

# Grep the From out of the body and add it to the header
ret = re.findall("From: (.*)", mail.get_payload())
mail.add_header("Bleeded-From", ret[0])

# Return the message
print(mail.as_string())

This is a very over simplyfied proove of concept and works only for non multipart messages without special characters. Otherwise this application will crash. Dealing with charsets would blow the margins of this example.

Community
  • 1
  • 1
Sprinterfreak
  • 504
  • 4
  • 10
  • Thank you ver ymuch for your answer! I'll get around my code to see how I can implement that great idea! ...and I'll have to remove special chars because I deal with french :-) Thank's again! – Satch Nov 07 '17 at 20:39