gurgitate-mail 1.10.9 → 1.10.10
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/gurgitate-mail.rb +386 -0
- data/lib/gurgitate/deliver.rb +87 -0
- data/lib/gurgitate/deliver/maildir.rb +104 -0
- data/lib/gurgitate/deliver/mbox.rb +47 -0
- data/lib/gurgitate/deliver/mh.rb +147 -0
- data/lib/gurgitate/header.rb +82 -0
- data/lib/gurgitate/headers.rb +283 -0
- data/lib/gurgitate/mail_headers.rb +167 -0
- data/lib/gurgitate/mailmessage.rb +142 -0
- data/lib/gurgitate/message.rb +114 -0
- data/test/test_delivery.rb +1 -1
- metadata +58 -65
@@ -0,0 +1,167 @@
|
|
1
|
+
#!/opt/bin/ruby -w
|
2
|
+
# -*- encoding : utf-8 -*-
|
3
|
+
|
4
|
+
require "gurgitate/headers"
|
5
|
+
|
6
|
+
module Gurgitate
|
7
|
+
class IllegalHeader < RuntimeError ; end
|
8
|
+
|
9
|
+
# ========================================================================
|
10
|
+
|
11
|
+
# A slightly bigger class for all of a message's headers
|
12
|
+
class MailHeaders < Headers
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
# Figures out whether the first line of a mail message is an
|
17
|
+
# mbox-style "From " line (say, if you get this from sendmail),
|
18
|
+
# or whether it's just a normal header.
|
19
|
+
# --
|
20
|
+
# If you run "fetchmail" with the -m option to feed the
|
21
|
+
# mail message straight to gurgitate, skipping the "local
|
22
|
+
# MTA" step, then it doesn't have a "From " line. So I
|
23
|
+
# have to deal with that by hand. First, check to see if
|
24
|
+
# there's a "From " line present in the first place.
|
25
|
+
def figure_out_from_line(headertext)
|
26
|
+
(unix_from,normal_headers) = headertext.split(/\n/,2)
|
27
|
+
|
28
|
+
if unix_from =~ /^From / then
|
29
|
+
headertext=normal_headers
|
30
|
+
unix_from=unix_from
|
31
|
+
else
|
32
|
+
# If there isn't, then deal with it after we've
|
33
|
+
# worried about the rest of the headers, 'cos we'll
|
34
|
+
# have to make our own.
|
35
|
+
unix_from=nil
|
36
|
+
end
|
37
|
+
return unix_from, headertext
|
38
|
+
end
|
39
|
+
|
40
|
+
# Get the envelope From information. This comes with a
|
41
|
+
# whole category of rants: this information is absurdly hard
|
42
|
+
# to get your hands on. The best you can manage is a sort
|
43
|
+
# of educated guess. Thus, this horrible glob of hackiness.
|
44
|
+
# I don't recommend looking too closely at this code if you
|
45
|
+
# can avoid it, and further I recommend making sure to
|
46
|
+
# configure your MTA so that it sends proper sender and
|
47
|
+
# recipient information to gurgitate so that this code never
|
48
|
+
# has to be run at all.
|
49
|
+
def guess_sender
|
50
|
+
# Start by worrying about the "From foo@bar" line. If it's
|
51
|
+
# not there, then make one up from the Return-Path: header.
|
52
|
+
# If there isn't a "Return-Path:" header (then I suspect we
|
53
|
+
# have bigger problems, but still) then use From: as a wild
|
54
|
+
# guess. If I hope that this entire lot of code doesn't get
|
55
|
+
# used, then I _particularly_ hope that things never get so
|
56
|
+
# bad that poor gurgitate has to use the From: header as a
|
57
|
+
# source of authoritative information on anything.
|
58
|
+
#
|
59
|
+
# And then after all that fuss, if we're delivering to a
|
60
|
+
# Maildir, I have to get rid of it. And sometimes the MTA
|
61
|
+
# gives me a mbox-style From line and sometimes it doesn't.
|
62
|
+
# It's annoying, but I have no choice but to Just Deal With
|
63
|
+
# It.
|
64
|
+
if @unix_from then
|
65
|
+
# If it is there, then grab the email address in it and
|
66
|
+
# use that as our official "from".
|
67
|
+
fromregex=/^From ([^ ]+@[^ ]+) /
|
68
|
+
fromregex.match(@unix_from)
|
69
|
+
@from=$+
|
70
|
+
|
71
|
+
# or maybe it's local
|
72
|
+
if @from == nil then
|
73
|
+
@unix_from =~ /^From (\S+) /
|
74
|
+
@from=$+
|
75
|
+
end
|
76
|
+
else
|
77
|
+
fromregex=/([^ ]+@[^ ]+) \(.*\)|[^<]*[<](.*@.*)[>]|([^ ]+@[^ ]+)/
|
78
|
+
if self["Return-Path"] != nil then
|
79
|
+
fromregex.match(self["Return-Path"][0].contents)
|
80
|
+
else
|
81
|
+
if self["From"] != nil then
|
82
|
+
fromregex.match(self["From"][0].contents)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
address_candidate=$+
|
86
|
+
|
87
|
+
# If there STILL isn't a match, then it's probably safe to
|
88
|
+
# assume that it's local mail, and doesn't have an @ in its
|
89
|
+
# address.
|
90
|
+
unless address_candidate
|
91
|
+
if self["Return-Path"] != nil then
|
92
|
+
self["Return-Path"][0].contents =~ /(\S+)/
|
93
|
+
address_candidate=$+
|
94
|
+
else
|
95
|
+
self["From"][0].contents =~ /(\S+)/
|
96
|
+
address_candidate=$+
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
@from=address_candidate
|
101
|
+
|
102
|
+
@unix_from="From "+self.from+" "+Time.new.to_s
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
public
|
107
|
+
|
108
|
+
# Creates a MailHeaders object.
|
109
|
+
# headertext::
|
110
|
+
# The text of the message headers.
|
111
|
+
def initialize(headertext=nil, sender=nil, recipient=nil)
|
112
|
+
@from = sender
|
113
|
+
@to = recipient
|
114
|
+
@headers = Hash.new(nil)
|
115
|
+
|
116
|
+
if Hash === headertext
|
117
|
+
@headers_changed = true
|
118
|
+
headertext.each_key do |key|
|
119
|
+
|
120
|
+
headername = key.to_s.gsub("_","-")
|
121
|
+
|
122
|
+
header=Header.new(headername, headertext[key])
|
123
|
+
@headers[header.name] ||= HeaderBag.new
|
124
|
+
@headers[header.name].push(header)
|
125
|
+
end
|
126
|
+
else
|
127
|
+
if headertext
|
128
|
+
@unix_from, @headertext = figure_out_from_line headertext
|
129
|
+
parse_headers if @headertext
|
130
|
+
|
131
|
+
if sender # then don't believe the mbox separator
|
132
|
+
@from = sender
|
133
|
+
@unix_from="From "+self.from+" "+Time.new.to_s
|
134
|
+
else
|
135
|
+
guess_sender
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
# Who the message is to (the envelope to)
|
142
|
+
#
|
143
|
+
# Yet another bucket of rants. Unix mail sucks.
|
144
|
+
def to
|
145
|
+
return @to || @headers["X-Original-To"] || nil
|
146
|
+
end
|
147
|
+
|
148
|
+
# Who the message is from (the envelope from)
|
149
|
+
def from
|
150
|
+
return @from || ""
|
151
|
+
end
|
152
|
+
|
153
|
+
# Change the envelope from line to whatever you want. This might
|
154
|
+
# not be particularly neighborly, but oh well.
|
155
|
+
# newfrom:: An email address
|
156
|
+
def from=(newfrom)
|
157
|
+
@from=newfrom
|
158
|
+
@unix_from="From "+self.from+" "+Time.new.to_s
|
159
|
+
end
|
160
|
+
|
161
|
+
# Returns the headers properly formatted for an mbox-format
|
162
|
+
# email message.
|
163
|
+
def to_mbox
|
164
|
+
return @unix_from+"\n"+to_s
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
# Contains the class Gurgitate::Mailmessage, used to handle the parsing
|
3
|
+
# of existing messages and the creation of new messages.
|
4
|
+
|
5
|
+
require 'gurgitate/headers'
|
6
|
+
require 'gurgitate/message'
|
7
|
+
|
8
|
+
module Gurgitate
|
9
|
+
|
10
|
+
# A complete mail message. This is the base class for
|
11
|
+
# gurgitate-mail itself: if you want to use gurgitate-mail to create
|
12
|
+
# new messages, this is what you want to use.
|
13
|
+
class Mailmessage < Message
|
14
|
+
|
15
|
+
Fromregex=/([^ ]+@[^ ]+) \(.*\)|[^<][<](.*@.*)[>]|([^ ]+@[^ ]+)/;
|
16
|
+
|
17
|
+
# The envelope sender and recipient, if anyone thought to
|
18
|
+
# mention them to us.
|
19
|
+
attr_accessor :sender
|
20
|
+
attr_accessor :recipient
|
21
|
+
|
22
|
+
# Creates a new mail message from the options hash, and the body of the
|
23
|
+
# message in a string.
|
24
|
+
#
|
25
|
+
# This can actually be invoked in several ways:
|
26
|
+
#
|
27
|
+
# Gurgitate::Mailmessage.create "This is the message body",
|
28
|
+
# :from => "from_address@example.com",
|
29
|
+
# :to => "to_address@example.com",
|
30
|
+
# :subject => "This is the message subject"
|
31
|
+
#
|
32
|
+
# This results in an email message that, when rendered via to_s, will
|
33
|
+
# look like this:
|
34
|
+
#
|
35
|
+
# From: from_address@example.com
|
36
|
+
# To: to_address@example.com
|
37
|
+
# Subject: This is the message subject
|
38
|
+
#
|
39
|
+
# This is the message body
|
40
|
+
#
|
41
|
+
# If you prefer to do things entirely by options hashes, as some do,
|
42
|
+
# you can substitute a :body key for the first argument:
|
43
|
+
#
|
44
|
+
# Gurgitate::Mailmessage.create(
|
45
|
+
# :body => "This is the message body",
|
46
|
+
# :from => "from_address@example.com",
|
47
|
+
# :to => "to_address@example.com",
|
48
|
+
# :subject => "This is the message subject"
|
49
|
+
# )
|
50
|
+
#
|
51
|
+
# There are two other special options you can use: :sender and
|
52
|
+
# :recipient. These are used to specify the sender and recipient of
|
53
|
+
# email messages, when the message is sent via SMTP.
|
54
|
+
#
|
55
|
+
def self.create(*args)
|
56
|
+
options = body = nil
|
57
|
+
|
58
|
+
if String === args[0]
|
59
|
+
options = args[1]
|
60
|
+
body = args[0]
|
61
|
+
elsif Hash === args[0]
|
62
|
+
options = args[0]
|
63
|
+
else
|
64
|
+
options = {}
|
65
|
+
end
|
66
|
+
|
67
|
+
message = self.new
|
68
|
+
|
69
|
+
message.instance_eval do
|
70
|
+
if body
|
71
|
+
@body=body
|
72
|
+
end
|
73
|
+
|
74
|
+
%w/sender recipient body/.each do |key|
|
75
|
+
if options.has_key? key.to_sym
|
76
|
+
instance_variable_set("@#{key}", options[key.to_sym])
|
77
|
+
options.delete key.to_sym
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
@headers = MailHeaders.new(options)
|
82
|
+
end
|
83
|
+
|
84
|
+
message
|
85
|
+
end
|
86
|
+
|
87
|
+
def initialize(text=nil, recipient=nil, sender=nil)
|
88
|
+
|
89
|
+
@recipient = recipient
|
90
|
+
@sender = sender
|
91
|
+
|
92
|
+
begin
|
93
|
+
# ASCII_8BIT is what Ruby 1.9 and up calls
|
94
|
+
# "binary stream of unknown encoding".
|
95
|
+
#
|
96
|
+
# At least it treats the ASCII characters
|
97
|
+
# as strings, so I can do regex things
|
98
|
+
# with them
|
99
|
+
text.force_encoding(Encoding::ASCII_8BIT)
|
100
|
+
rescue NameError # Ruby 1.9 and up
|
101
|
+
true
|
102
|
+
end
|
103
|
+
|
104
|
+
if text
|
105
|
+
(@headertext,@body)=text.split(/\n\n/m,2)
|
106
|
+
@headers=MailHeaders.new(@headertext);
|
107
|
+
Fromregex.match(
|
108
|
+
if @headers["From"] then
|
109
|
+
@headers["From"][0].contents
|
110
|
+
else
|
111
|
+
""
|
112
|
+
end);
|
113
|
+
@from=$+
|
114
|
+
else
|
115
|
+
super(text)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# custom accessors
|
120
|
+
|
121
|
+
# Returns the message's sender
|
122
|
+
def from; @sender || @headers.from; end
|
123
|
+
|
124
|
+
# Returns all the candidates for a recipient
|
125
|
+
def to
|
126
|
+
if @recipient
|
127
|
+
then @recipient
|
128
|
+
elsif @headers["To"]
|
129
|
+
then @headers["To"][0].contents
|
130
|
+
elsif @headers["Cc"]
|
131
|
+
then @headers["Cc"][0].contents
|
132
|
+
elsif @headers["X-Original-To"]
|
133
|
+
then @headers["X-Original-To"][0].contents
|
134
|
+
else
|
135
|
+
""
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
# Returns the mail message formatted for mbox
|
140
|
+
def to_mbox; @headers.to_mbox + "\n\n" + @body; end
|
141
|
+
end
|
142
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
#!/opt/bin/ruby -w
|
2
|
+
# -*- encoding : utf-8 -*-
|
3
|
+
|
4
|
+
#------------------------------------------------------------------------
|
5
|
+
# Handles a complete mail message
|
6
|
+
#------------------------------------------------------------------------
|
7
|
+
|
8
|
+
require 'gurgitate/mail_headers'
|
9
|
+
|
10
|
+
module Gurgitate
|
11
|
+
|
12
|
+
# A complete mail message.
|
13
|
+
class Message
|
14
|
+
|
15
|
+
# The headers of the message
|
16
|
+
attr_reader :headers
|
17
|
+
# The body of the message
|
18
|
+
attr_accessor :body
|
19
|
+
|
20
|
+
# Creates a new message from the options hash, and the body of the
|
21
|
+
# message in a string.
|
22
|
+
#
|
23
|
+
# This can actually be invoked in several ways:
|
24
|
+
#
|
25
|
+
# Gurgitate::Mailmessage.create "This is the message body",
|
26
|
+
# :from => "from_address@example.com",
|
27
|
+
# :to => "to_address@example.com",
|
28
|
+
# :subject => "This is the message subject"
|
29
|
+
#
|
30
|
+
# This results in an email message that, when rendered via to_s, will
|
31
|
+
# look like this:
|
32
|
+
#
|
33
|
+
# From: from_address@example.com
|
34
|
+
# To: to_address@example.com
|
35
|
+
# Subject: This is the message subject
|
36
|
+
#
|
37
|
+
# This is the message body
|
38
|
+
#
|
39
|
+
# If you prefer to do things entirely by options hashes, as some do,
|
40
|
+
# you can substitute a :body key for the first argument:
|
41
|
+
#
|
42
|
+
# Gurgitate::Mailmessage.create(
|
43
|
+
# :body => "This is the message body",
|
44
|
+
# :from => "from_address@example.com",
|
45
|
+
# :to => "to_address@example.com",
|
46
|
+
# :subject => "This is the message subject"
|
47
|
+
# )
|
48
|
+
#
|
49
|
+
# There are two other special options you can use: :sender and
|
50
|
+
# :recipient. These are used to specify the sender and recipient of
|
51
|
+
# email messages, when the message is sent via SMTP.
|
52
|
+
#
|
53
|
+
def self.create(*args)
|
54
|
+
options = body = nil
|
55
|
+
|
56
|
+
if String === args[0]
|
57
|
+
options = args[1]
|
58
|
+
body = args[0]
|
59
|
+
elsif Hash === args[0]
|
60
|
+
options = args[0]
|
61
|
+
else
|
62
|
+
options = {}
|
63
|
+
end
|
64
|
+
|
65
|
+
message = self.new
|
66
|
+
|
67
|
+
message.instance_eval do
|
68
|
+
if body
|
69
|
+
@body=body
|
70
|
+
end
|
71
|
+
|
72
|
+
@headers = Headers.new(options)
|
73
|
+
end
|
74
|
+
|
75
|
+
message
|
76
|
+
end
|
77
|
+
|
78
|
+
# Creates a new Gurgitate message from a pre-existing message.
|
79
|
+
# This is what is used when gurgitate-mail is used as a mail filter.
|
80
|
+
#
|
81
|
+
# ARGUMENTS::
|
82
|
+
# +text+ :: An RFC822-formatted message.
|
83
|
+
# +recipient+ :: The recipient of the email message, from the MTA
|
84
|
+
# +sender+ :: The sender of the email message, also from the MTA
|
85
|
+
#
|
86
|
+
# All of its arguments can be nil: if called with no arguments,
|
87
|
+
# it simply returns an empty email message, which can be populated
|
88
|
+
# after the fact.
|
89
|
+
def initialize(text=nil)
|
90
|
+
if text
|
91
|
+
(@headertext,@body)=text.split(/\n\n/,2)
|
92
|
+
@headers=Headers.new(@headertext);
|
93
|
+
else
|
94
|
+
@headers = Headers.new
|
95
|
+
@body = ""
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# Returns the header +name+, which is, note, a HeaderBag of all
|
100
|
+
# headers by that name, not just a single header.
|
101
|
+
#
|
102
|
+
# If you want the text of the header, then you have to coerce it to a
|
103
|
+
# string:
|
104
|
+
#
|
105
|
+
# header("name").to_s
|
106
|
+
#
|
107
|
+
def header(name)
|
108
|
+
@headers[name].each { |h| h.contents }.join(", ")
|
109
|
+
end
|
110
|
+
|
111
|
+
# Returns the formatted mail message
|
112
|
+
def to_s; @headers.to_s + "\n\n" + ( @body || ""); end
|
113
|
+
end
|
114
|
+
end
|
data/test/test_delivery.rb
CHANGED
metadata
CHANGED
@@ -1,98 +1,91 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: gurgitate-mail
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
prerelease:
|
6
|
-
segments:
|
7
|
-
- 1
|
8
|
-
- 10
|
9
|
-
- 9
|
10
|
-
version: 1.10.9
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.10.10
|
11
5
|
platform: ruby
|
12
|
-
authors:
|
6
|
+
authors:
|
13
7
|
- Dave Brown
|
14
8
|
autorequire:
|
15
9
|
bindir: bin
|
16
10
|
cert_chain: []
|
17
|
-
|
18
|
-
date: 2013-06-04 00:00:00 Z
|
11
|
+
date: 2015-02-05 00:00:00.000000000 Z
|
19
12
|
dependencies: []
|
20
|
-
|
21
|
-
|
13
|
+
description: |2
|
14
|
+
gurgitate-mail is a mail filter. It can be used as a module or
|
15
|
+
as a standalone application.
|
22
16
|
email: gurgitate-mail@dagbrown.com
|
23
|
-
executables:
|
17
|
+
executables:
|
24
18
|
- gurgitate-mail
|
25
19
|
extensions: []
|
26
|
-
|
27
20
|
extra_rdoc_files: []
|
28
|
-
|
29
|
-
|
21
|
+
files:
|
22
|
+
- ".gemtest"
|
23
|
+
- Rakefile
|
24
|
+
- bin/gurgitate-mail
|
25
|
+
- lib/gurgitate-mail.rb
|
26
|
+
- lib/gurgitate/deliver.rb
|
27
|
+
- lib/gurgitate/deliver/maildir.rb
|
28
|
+
- lib/gurgitate/deliver/mbox.rb
|
29
|
+
- lib/gurgitate/deliver/mh.rb
|
30
|
+
- lib/gurgitate/header.rb
|
31
|
+
- lib/gurgitate/headers.rb
|
32
|
+
- lib/gurgitate/mail_headers.rb
|
33
|
+
- lib/gurgitate/mailmessage.rb
|
34
|
+
- lib/gurgitate/message.rb
|
35
|
+
- test/gurgitate-test.rb
|
30
36
|
- test/runtests.rb
|
31
|
-
- test/test_writing.rb
|
32
|
-
- test/test_rules.rb
|
33
|
-
- test/test_header.rb
|
34
|
-
- test/test_gurgitate_delivery.rb
|
35
|
-
- test/test_process.rb
|
36
|
-
- test/test_deliver.rb
|
37
37
|
- test/test_configuration.rb
|
38
|
-
- test/
|
39
|
-
- test/test_mail_headers.rb
|
38
|
+
- test/test_deliver.rb
|
40
39
|
- test/test_delivery.rb
|
41
|
-
- test/test_headers_creating_from_hash.rb
|
42
|
-
- test/test_headers_meddling_with_headers.rb
|
43
40
|
- test/test_execute_rules.rb
|
41
|
+
- test/test_gurgitate_delivery.rb
|
42
|
+
- test/test_header.rb
|
44
43
|
- test/test_headers.rb
|
44
|
+
- test/test_headers_creating_from_hash.rb
|
45
|
+
- test/test_headers_meddling_with_headers.rb
|
46
|
+
- test/test_mail_headers.rb
|
45
47
|
- test/test_mail_headers_meddling_with_headers.rb
|
46
|
-
- .
|
47
|
-
-
|
48
|
-
-
|
49
|
-
homepage: http://www.
|
50
|
-
licenses:
|
51
|
-
|
48
|
+
- test/test_process.rb
|
49
|
+
- test/test_rules.rb
|
50
|
+
- test/test_writing.rb
|
51
|
+
homepage: http://www.github.com/dagbrown/gurgitate-mail/
|
52
|
+
licenses:
|
53
|
+
- GPL-2.0
|
54
|
+
metadata: {}
|
52
55
|
post_install_message:
|
53
56
|
rdoc_options: []
|
54
|
-
|
55
|
-
require_paths:
|
57
|
+
require_paths:
|
56
58
|
- lib
|
57
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
58
|
-
|
59
|
-
requirements:
|
59
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
60
61
|
- - ">="
|
61
|
-
- !ruby/object:Gem::Version
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
version: "0"
|
66
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
67
|
-
none: false
|
68
|
-
requirements:
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '0'
|
64
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
69
66
|
- - ">="
|
70
|
-
- !ruby/object:Gem::Version
|
71
|
-
|
72
|
-
segments:
|
73
|
-
- 0
|
74
|
-
version: "0"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
75
69
|
requirements: []
|
76
|
-
|
77
|
-
|
78
|
-
rubygems_version: 1.8.24
|
70
|
+
rubyforge_project:
|
71
|
+
rubygems_version: 2.4.5
|
79
72
|
signing_key:
|
80
|
-
specification_version:
|
73
|
+
specification_version: 4
|
81
74
|
summary: gurgitate-mail is a mail filter (and a mail-delivery agent)
|
82
|
-
test_files:
|
83
|
-
- test/runtests.rb
|
75
|
+
test_files:
|
84
76
|
- test/test_writing.rb
|
77
|
+
- test/test_headers_meddling_with_headers.rb
|
85
78
|
- test/test_rules.rb
|
86
|
-
- test/
|
79
|
+
- test/test_execute_rules.rb
|
80
|
+
- test/test_mail_headers.rb
|
87
81
|
- test/test_gurgitate_delivery.rb
|
88
|
-
- test/
|
82
|
+
- test/runtests.rb
|
89
83
|
- test/test_deliver.rb
|
84
|
+
- test/test_process.rb
|
85
|
+
- test/test_mail_headers_meddling_with_headers.rb
|
90
86
|
- test/test_configuration.rb
|
91
|
-
- test/
|
92
|
-
- test/test_mail_headers.rb
|
87
|
+
- test/test_header.rb
|
93
88
|
- test/test_delivery.rb
|
94
89
|
- test/test_headers_creating_from_hash.rb
|
95
|
-
- test/
|
96
|
-
- test/test_execute_rules.rb
|
90
|
+
- test/gurgitate-test.rb
|
97
91
|
- test/test_headers.rb
|
98
|
-
- test/test_mail_headers_meddling_with_headers.rb
|