<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 TRANSITIONAL//EN">
<HTML>
<HEAD>
  <META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=UTF-8">
  <META NAME="GENERATOR" CONTENT="GtkHTML/3.30.3">
</HEAD>
<BODY>
On Sat, 2010-10-23 at 14:07 -0700, Tony Cratz wrote:
<BLOCKQUOTE TYPE=CITE>
<PRE>
On 10/21/2010 11:21 AM, Ken Bloom wrote:
&gt; That's why I suggested GNU mailutils. It has a &quot;sieve&quot; command that
&gt; looks like it's a standalone filter (procmail replacement).


        I would like to come back to this and ask a question just
        in case I did not see what I should have.

        Do you know if Sieve can rewrite headers. For example can I
        change the To: header, or the Subject: header.
</PRE>
</BLOCKQUOTE>
<BR>
A quick googling suggests it doesn't know how to do it in-process, but you could use the GNU mailutils pipe extension to do such things (in conjunction with a program like formail or reformail, or of course a spam filter like spamassassin). You can look in /usr/lib/mailutils/ to see what extensions are available, and you can write your own as a shared library.
<BLOCKQUOTE TYPE=CITE>
<PRE>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; And if the
        answer is yeas, then can I take the new message and send it
        to my SMTP server (such as Sendmail) to redeliver the message
        to the new list?
</PRE>
</BLOCKQUOTE>
<BR>
<BLOCKQUOTE TYPE=CITE>
<PRE>
        Maildrop was also mention, I only took a quick and dirty look
        at it. Can it also solve the above questions?
</PRE>
</BLOCKQUOTE>
<BR>
I don't actually use Sieve for my email. I suggested it because it was a standard.<BR>
<BR>
I've used maildrop in the past (rewriting headers, and running spam filters with its xfilter command), and my mail filters looked like (for example)<BR>
<BR>
<BLOCKQUOTE>
<PRE>
if (/Mailing-List: list <A HREF="mailto:NAJSA@yahoogroups.com">some.mailinglist.org</A>; contact/:h ||        \
&nbsp;&nbsp;&nbsp; /From:.*foo@bar.com/ || \
&nbsp;&nbsp;&nbsp; /From:.*bar@foo.com/ || \
&nbsp;&nbsp;&nbsp; /From:.*baz@bar.com/ || \
&nbsp;&nbsp;&nbsp; /From:.*@some.domain.org/ || \
&nbsp;&nbsp;&nbsp; /Mailing-List: list some-other-mailinglist@yahoogroups.com; / || \
&nbsp;&nbsp;&nbsp; /From:.*afinal@email.org/ )
{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; to $MAILBOX/.util.probably-spam
}

# spam filtering
if ($SIZE &lt; 1048576)
{
&nbsp;&nbsp; xfilter 'spamassassin'
}

if (/^X-Spam-Status: Yes/)
{
&nbsp;&nbsp; xfilter 'reformail -I&quot;Status: RO&quot;'
&nbsp;&nbsp; to '| $HOME/bin/maildir-deliverread $MAILBOX/.util.probably-spam'
}
</PRE>
</BLOCKQUOTE>
<PRE>

</PRE>
I didn't like this (I didn't find it concise enough), and the backslashes as line continuations and mandatory braces annoyed me. (I was always forgetting them when I made changes, and it would break my email for days on end.)<BR>
<BR>
So I changed to a solution in Ruby. I tried Perl first, but Perl performs variable interpolation with the @ sigil, so you can't put email addresses in a regular expression in Perl without escaping them. You'll notice that I don't bother to escape the period metacharacter in my regular expressions. Though technically, it can match any character, that possibility for false positives doesn't seem to matter much.<BR>
<BR>
 First, here's the skeleton that you need to write your own version. (You'll probably want to redefine the saveread function so that it doesn't depend on an external script.)<BR>
<BR>
<BLOCKQUOTE>
<PRE>
#!/usr/bin/env ruby
require 'rfilter/delivery_agent'
class RFilter::DeliveryAgent

&nbsp;&nbsp; def myfilter
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #RULES GO IN HERE
&nbsp;&nbsp; end

&nbsp;&nbsp; #SUPPORT CODE FOLLOWS
&nbsp; 

&nbsp;&nbsp; def self.header_accessor name,field
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; class_eval &lt;&lt;-&quot;end;&quot;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; def #{name}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; header[&quot;#{field}&quot;] || &quot;&quot;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end;
&nbsp;&nbsp; end

&nbsp;&nbsp; header_accessor :from, &quot;From&quot;
&nbsp;&nbsp; header_accessor :to, &quot;To&quot;
&nbsp;&nbsp; header_accessor :listid, &quot;List-Id&quot;
&nbsp;&nbsp; header_accessor :spam, &quot;X-Spam-Status&quot;
&nbsp;&nbsp; header_accessor :subject, &quot;Subject&quot;
&nbsp;&nbsp; header_accessor :msgid, &quot;Message-id&quot;
&nbsp;&nbsp; header_accessor :cc, &quot;CC&quot;

&nbsp;&nbsp; def isto? pattern
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; not [to,cc].grep(pattern).empty?
&nbsp;&nbsp; end
&nbsp;&nbsp; def involves? pattern
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; not [from,to,cc].grep(pattern).empty?
&nbsp;&nbsp; end

&nbsp;&nbsp; def ignore mailbox
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; saveread &quot;.ignored-summer&quot;
&nbsp;&nbsp; end

&nbsp;&nbsp; alias_method :internal_save, :save
&nbsp;&nbsp; def saveto mailbox
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; internal_save &quot;#{ENV['HOME']}/Maildir/#{mailbox}/&quot;
&nbsp;&nbsp; end
&nbsp;&nbsp; alias_method :save, :saveto

&nbsp;&nbsp; def saveread mailbox
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pipe &quot;#{ENV['HOME']}/bin/maildir-deliverread #{ENV['HOME']}/Maildir/#{mailbox}/&quot;
&nbsp;&nbsp; end

&nbsp;&nbsp; def discard
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pipe &quot;true&quot;
&nbsp;&nbsp; end

&nbsp;&nbsp; def main
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; myfilter
&nbsp;&nbsp; end

end

begin
&nbsp;&nbsp; RFilter::DeliveryAgent.process(STDIN,nil) { |agent| agent.main }
rescue RFilter::DeliveryAgent::DeliverySuccess
end
</PRE>
</BLOCKQUOTE>
<BR>
Then you can write really concise rules that look like this. (Any call to a save function or discard function stops the filter right there.)<BR>
<BR>
<PRE>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; discard if from =~ /noreply@studygroup.com/
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; discard if from =~ /Walgreens@email.walgreens.com/
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; saveto &quot;.computer&quot; if header[&quot;Return-Path&quot;] =~ /cat-in-the-hat/
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; saveto &quot;.computer&quot; if header[&quot;Return-Path&quot;] =~ /little-cat-a/
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; saveto &quot;.computer&quot; if from =~ /cat-in-the-hat/
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; saveto &quot;.computer&quot; if from =~ /little-cat-a/

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #this is on multiple lines only because the test is so long that
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #it would have wrapped badly otherwise
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if involves?(/someparticularperson@somedomain.com/)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; saveto &quot;.somefolder&quot;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; saveto &quot;.lists.linux&quot; if listid =~ /.*vox.*lugod/

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if from =~ /messages@frumster.com/
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; saveto &quot;.shidduchim&quot; if subject =~ /sent you a message/i
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; saveto &quot;.shidduchim&quot; if subject =~ /I want to communicate with you/i
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; saveread &quot;.shidduchim&quot;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if message.to_s.length &lt; 1048576
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; filter &quot;spamassassin&quot;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if spam =~ /^Yes/
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; saveread &quot;.util.probably-spam&quot;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end
</PRE>
<BR>
You can even modify headers in process:<BR>
<BR>
<PRE>
&nbsp;&nbsp;&nbsp;&nbsp; if from =~ /acl@aclweb.org/ or from =~ /portal@aclweb.org/
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #Can't use sub! because the original string is frozen.
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; message.header.subject=subject.sub('[na_members@aclweb.org] ','')
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; saveto &quot;.lists.ACL&quot;
&nbsp;&nbsp;&nbsp;&nbsp; end
</PRE>
<BR>
<BR>
<BR>
How are you rewriting headers in procmail? Is this done by piping, or in-process?
</BODY>
</HTML>