<!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:
> That's why I suggested GNU mailutils. It has a "sieve" command that
> 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>
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 ||        \
/From:.*foo@bar.com/ || \
/From:.*bar@foo.com/ || \
/From:.*baz@bar.com/ || \
/From:.*@some.domain.org/ || \
/Mailing-List: list some-other-mailinglist@yahoogroups.com; / || \
/From:.*afinal@email.org/ )
{
to $MAILBOX/.util.probably-spam
}
# spam filtering
if ($SIZE < 1048576)
{
xfilter 'spamassassin'
}
if (/^X-Spam-Status: Yes/)
{
xfilter 'reformail -I"Status: RO"'
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
def myfilter
#RULES GO IN HERE
end
#SUPPORT CODE FOLLOWS
def self.header_accessor name,field
class_eval <<-"end;"
def #{name}
header["#{field}"] || ""
end
end;
end
header_accessor :from, "From"
header_accessor :to, "To"
header_accessor :listid, "List-Id"
header_accessor :spam, "X-Spam-Status"
header_accessor :subject, "Subject"
header_accessor :msgid, "Message-id"
header_accessor :cc, "CC"
def isto? pattern
not [to,cc].grep(pattern).empty?
end
def involves? pattern
not [from,to,cc].grep(pattern).empty?
end
def ignore mailbox
saveread ".ignored-summer"
end
alias_method :internal_save, :save
def saveto mailbox
internal_save "#{ENV['HOME']}/Maildir/#{mailbox}/"
end
alias_method :save, :saveto
def saveread mailbox
pipe "#{ENV['HOME']}/bin/maildir-deliverread #{ENV['HOME']}/Maildir/#{mailbox}/"
end
def discard
pipe "true"
end
def main
myfilter
end
end
begin
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>
discard if from =~ /noreply@studygroup.com/
discard if from =~ /Walgreens@email.walgreens.com/
saveto ".computer" if header["Return-Path"] =~ /cat-in-the-hat/
saveto ".computer" if header["Return-Path"] =~ /little-cat-a/
saveto ".computer" if from =~ /cat-in-the-hat/
saveto ".computer" if from =~ /little-cat-a/
#this is on multiple lines only because the test is so long that
#it would have wrapped badly otherwise
if involves?(/someparticularperson@somedomain.com/)
saveto ".somefolder"
end
saveto ".lists.linux" if listid =~ /.*vox.*lugod/
if from =~ /messages@frumster.com/
saveto ".shidduchim" if subject =~ /sent you a message/i
saveto ".shidduchim" if subject =~ /I want to communicate with you/i
saveread ".shidduchim"
end
if message.to_s.length < 1048576
filter "spamassassin"
end
if spam =~ /^Yes/
saveread ".util.probably-spam"
end
</PRE>
<BR>
You can even modify headers in process:<BR>
<BR>
<PRE>
if from =~ /acl@aclweb.org/ or from =~ /portal@aclweb.org/
#Can't use sub! because the original string is frozen.
message.header.subject=subject.sub('[na_members@aclweb.org] ','')
saveto ".lists.ACL"
end
</PRE>
<BR>
<BR>
<BR>
How are you rewriting headers in procmail? Is this done by piping, or in-process?
</BODY>
</HTML>