mlist 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +59 -0
- data/README +204 -0
- data/Rakefile +27 -0
- data/TODO +36 -0
- data/VERSION.yml +4 -0
- data/lib/mlist/email.rb +69 -0
- data/lib/mlist/email_post.rb +126 -0
- data/lib/mlist/email_server/base.rb +33 -0
- data/lib/mlist/email_server/default.rb +31 -0
- data/lib/mlist/email_server/fake.rb +16 -0
- data/lib/mlist/email_server/pop.rb +28 -0
- data/lib/mlist/email_server/smtp.rb +24 -0
- data/lib/mlist/email_server.rb +2 -0
- data/lib/mlist/email_subscriber.rb +6 -0
- data/lib/mlist/list.rb +183 -0
- data/lib/mlist/mail_list.rb +277 -0
- data/lib/mlist/manager/database.rb +48 -0
- data/lib/mlist/manager/notifier.rb +31 -0
- data/lib/mlist/manager.rb +30 -0
- data/lib/mlist/message.rb +150 -0
- data/lib/mlist/server.rb +62 -0
- data/lib/mlist/thread.rb +98 -0
- data/lib/mlist/util/email_helpers.rb +155 -0
- data/lib/mlist/util/header_sanitizer.rb +71 -0
- data/lib/mlist/util/quoting.rb +70 -0
- data/lib/mlist/util/tmail_builder.rb +42 -0
- data/lib/mlist/util/tmail_methods.rb +138 -0
- data/lib/mlist/util.rb +12 -0
- data/lib/mlist.rb +46 -0
- data/lib/pop_ssl.rb +999 -0
- data/rails/init.rb +22 -0
- data/spec/fixtures/schema.rb +94 -0
- data/spec/integration/date_formats_spec.rb +12 -0
- data/spec/integration/mlist_spec.rb +232 -0
- data/spec/integration/pop_email_server_spec.rb +22 -0
- data/spec/integration/proof_spec.rb +74 -0
- data/spec/matchers/equal_tmail.rb +53 -0
- data/spec/matchers/have_address.rb +48 -0
- data/spec/matchers/have_header.rb +104 -0
- data/spec/models/email_post_spec.rb +100 -0
- data/spec/models/email_server/base_spec.rb +11 -0
- data/spec/models/email_spec.rb +54 -0
- data/spec/models/mail_list_spec.rb +469 -0
- data/spec/models/message_spec.rb +109 -0
- data/spec/models/thread_spec.rb +83 -0
- data/spec/models/util/email_helpers_spec.rb +47 -0
- data/spec/models/util/header_sanitizer_spec.rb +19 -0
- data/spec/models/util/quoting_spec.rb +96 -0
- data/spec/spec_helper.rb +76 -0
- metadata +103 -0
@@ -0,0 +1,109 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe MList::Message do
|
4
|
+
include MList::Util::EmailHelpers
|
5
|
+
|
6
|
+
before do
|
7
|
+
@tmail = tmail_fixture('single_list')
|
8
|
+
@email = MList::Email.new(:tmail => @tmail)
|
9
|
+
@message = MList::Message.new(:email => @email)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should capture the mailer header' do
|
13
|
+
@message.mailer.should == 'Apple Mail (2.929.2)'
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should capture the subject' do
|
17
|
+
@message.subject.should == 'Test'
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should not modify the original email' do
|
21
|
+
mock(@email)
|
22
|
+
@message.subject = 'modified'
|
23
|
+
@message.mailer = 'modified'
|
24
|
+
@message.identifier = 'modified'
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should answer a subject suitable for replies' do
|
28
|
+
@message.subject = '[List Label] The new Chrome Browser from Google'
|
29
|
+
@message.subject_for_reply.should == 'Re: [List Label] The new Chrome Browser from Google'
|
30
|
+
|
31
|
+
@message.subject = 'Re: [List Label] The new Chrome Browser from Google'
|
32
|
+
@message.subject_for_reply.should == 'Re: [List Label] The new Chrome Browser from Google'
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should save the associated email' do
|
36
|
+
@message.save!
|
37
|
+
@message = MList::Message.find(@message.id)
|
38
|
+
@message.email.source.should == email_fixture('single_list')
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should delete the email when message destroyed' do
|
42
|
+
@message.save!
|
43
|
+
@message.destroy
|
44
|
+
MList::Email.exists?(@email).should be_false
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should not delete the email if other messages reference it' do
|
48
|
+
@message.save!
|
49
|
+
MList::Message.create!(:mail_list_id => 234234, :email => @email)
|
50
|
+
@message.destroy
|
51
|
+
MList::Email.exists?(@email).should be_true
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe MList::Message, 'text' do
|
56
|
+
def message_from_tmail(path)
|
57
|
+
tmail = tmail_fixture(path)
|
58
|
+
email = MList::Email.new(:tmail => tmail)
|
59
|
+
MList::Message.new(:email => email)
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'should work with text/plain' do
|
63
|
+
message_from_tmail('content_types/text_plain').text.should == 'Hello there'
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'should work with multipart/alternative, simple' do
|
67
|
+
message_from_tmail('content_types/multipart_alternative_simple').text.should ==
|
68
|
+
"This is just a simple test.\n\nThis line should be bold.\n\nThis line should be italic."
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'should work with mutltipart/mixed, outlook' do
|
72
|
+
message_from_tmail('content_types/multipart_mixed_outlook').text.should ==
|
73
|
+
"This is a simple test."
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'should work with multipart/related, no text part' do
|
77
|
+
message_from_tmail('content_types/multipart_related_no_text_plain').text.should == %(I don't really have much to say, so I'm going to share some random things I saw today:
|
78
|
+
|
79
|
+
I saw this guy on twitter.com, and he looks pretty chill:
|
80
|
+
|
81
|
+
I found this sweet url, and it's not dirty!:
|
82
|
+
|
83
|
+
I found out that if I call our Skype phone from Skype on my laptop, my laptop will give me the ability to answer the call I am placing. Freaky!
|
84
|
+
|
85
|
+
Here is what my rating star widget looks like:
|
86
|
+
|
87
|
+
What's with the dashes and tildes?
|
88
|
+
|
89
|
+
Yeah, what is going on with that. They don't even match.
|
90
|
+
-~----~~----~----~----~----~---~~-~----~------~--~-~-
|
91
|
+
vs
|
92
|
+
--~--~---~~----~--~----~-----~~~----~---~---~--~-~--~
|
93
|
+
|
94
|
+
|
95
|
+
Good job with this!
|
96
|
+
|
97
|
+
-Steve)
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'should answer text suitable for reply' do
|
101
|
+
message_from_tmail('content_types/text_plain').text_for_reply.should ==
|
102
|
+
email_fixture('content_types/text_plain_reply.txt')
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'should answer html suitable for reply' do
|
106
|
+
message_from_tmail('content_types/text_plain').html_for_reply.should ==
|
107
|
+
email_fixture('content_types/text_plain_reply.html')
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe MList::Thread do
|
4
|
+
before do
|
5
|
+
@messages = (1..3).map {|i| m = MList::Message.new; stub(m).subject {i.to_s}; m}
|
6
|
+
@thread = MList::Thread.new
|
7
|
+
stub(@thread).messages {@messages}
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'should answer subject by way of the first message' do
|
11
|
+
@thread.subject.should == '1'
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should have messages counted' do
|
15
|
+
MList::Message.reflect_on_association(:thread).counter_cache_column.should == :messages_count
|
16
|
+
MList::Thread.column_names.should include('messages_count')
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe MList::Thread, 'tree' do
|
21
|
+
before do
|
22
|
+
@messages = (1..5).map {|i| m = MList::Message.new; m.id = i; m}
|
23
|
+
@messages[1].parent_id = @messages[0].id
|
24
|
+
@messages[2].parent_id = @messages[1].id
|
25
|
+
@messages[3].parent_id = @messages[0].id
|
26
|
+
@messages[4].parent_id = @messages[3].id
|
27
|
+
|
28
|
+
@thread = MList::Thread.new
|
29
|
+
stub(@thread).messages {@messages}
|
30
|
+
|
31
|
+
@tree = @thread.tree
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should answer the first message as the root of the tree' do
|
35
|
+
@tree.should == @messages[0]
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'should connect the nodes into a tree' do
|
39
|
+
@tree.children.should == [@messages[1], @messages[3]]
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should connect next and previous to each node' do
|
43
|
+
@tree.previous.should be_nil
|
44
|
+
@tree.next.should == @messages[1]
|
45
|
+
@tree.next.previous.should == @messages[0]
|
46
|
+
@tree.next.next.should == @messages[2]
|
47
|
+
@tree.next.next.next.should == @messages[3]
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should know if a message is the root' do
|
51
|
+
@tree.root?.should be_true
|
52
|
+
@tree.next.root?.should be_false
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'should know if a message is a leaf' do
|
56
|
+
@tree.leaf?.should be_false
|
57
|
+
@tree.next.leaf?.should be_false
|
58
|
+
@tree.next.next.leaf?.should be_true
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'should answer when a message is last in the thread' do
|
62
|
+
@thread.first?(@messages[0]).should be_true
|
63
|
+
@thread.first?(@messages[1]).should be_false
|
64
|
+
@thread.first?(@messages[2]).should be_false
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'should answer when a message is last in the thread' do
|
68
|
+
@thread.last?(@messages[0]).should be_false
|
69
|
+
@thread.last?(@messages[1]).should be_false
|
70
|
+
@thread.last?(@messages[4]).should be_true
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'should answer the message next to given' do
|
74
|
+
@thread.next(@messages[0]).should == @messages[1]
|
75
|
+
@thread.next(@messages[2]).should == @messages[3]
|
76
|
+
@thread.next(@messages[4]).should be_nil
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'should answer the message previous to given' do
|
80
|
+
@thread.previous(@messages[0]).should be_nil
|
81
|
+
@thread.previous(@messages[2]).should == @messages[1]
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
+
|
3
|
+
describe MList::Util::EmailHelpers do
|
4
|
+
include MList::Util::EmailHelpers
|
5
|
+
|
6
|
+
%w(nothing_special ascii_art reply_quoting reply_quoting_deeper bullets bullets_leading_space).each do |text_source_name|
|
7
|
+
specify "text_to_html should convert #{text_source_name}" do
|
8
|
+
source_text = text_fixture(text_source_name)
|
9
|
+
expected_text = text_fixture("#{text_source_name}.html")
|
10
|
+
text_to_html(source_text).should == expected_text
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
specify 'text_to_quoted should prepend >' do
|
15
|
+
text_to_quoted(text_fixture('nothing_special')).should == text_fixture('nothing_special_quoted')
|
16
|
+
end
|
17
|
+
|
18
|
+
describe 'remove_regard' do
|
19
|
+
it 'should remove regardless of case' do
|
20
|
+
remove_regard('Re: [Label] Subject').should == '[Label] Subject'
|
21
|
+
remove_regard('RE: [Label] Subject').should == '[Label] Subject'
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should not bother [] labels when multiple re:' do
|
25
|
+
remove_regard('Re: [Label] Re: Subject').should == '[Label] Subject'
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should remove multiple re:' do
|
29
|
+
remove_regard('Re: Re: Test').should == 'Test'
|
30
|
+
remove_regard('Re: Re: Subject').should == 'Subject'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe 'html_to_text' do
|
35
|
+
it 'should handle real life example' do
|
36
|
+
html_to_text(html_fixture('real_life')).should == html_fixture('real_life.txt')
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should handle lists' do
|
40
|
+
html_to_text('<p>Fruits</p> <ul><li>Apples</li><li>Oranges</li><li>Bananas</li></ul>').should == %{Fruits\n\n * Apples\n\n * Oranges\n\n * Bananas}
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should handle lots of non-breaking space' do
|
44
|
+
html_to_text(html_fixture('nbsp')).should == html_fixture('nbsp.txt')
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
+
|
3
|
+
describe MList::Util::HeaderSanitizerHash do
|
4
|
+
before do
|
5
|
+
@sanitizer = MList::Util::HeaderSanitizerHash.new
|
6
|
+
end
|
7
|
+
|
8
|
+
%w(to cc bcc from reply-to).each do |header|
|
9
|
+
it %Q{should escape " and \\ in address phrase for #{header}} do
|
10
|
+
@sanitizer[header].call('UTF-8', '"Johnny " Dangerously \" <johnny@nomail.net>').should == ['"Johnny \" Dangerously \\\\" <johnny@nomail.net>']
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
%w(sender errors-to).each do |header|
|
15
|
+
it %Q{should escape " in address phrase for #{header}} do
|
16
|
+
@sanitizer[header].call('UTF-8', '"Johnny " Dangerously \" <johnny@nomail.net>').should == '"Johnny \" Dangerously \\\\" <johnny@nomail.net>'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
+
|
3
|
+
require 'tempfile'
|
4
|
+
|
5
|
+
describe MList::Util::Quoting do
|
6
|
+
# Move some tests from TMAIL here
|
7
|
+
it 'should unquote quoted printable' do
|
8
|
+
a ="=?ISO-8859-1?Q?[166417]_Bekr=E6ftelse_fra_Rejsefeber?="
|
9
|
+
b = TMail::Unquoter.unquote_and_convert_to(a, 'utf-8')
|
10
|
+
b.should == "[166417] Bekr\303\246ftelse fra Rejsefeber"
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should unquote base64' do
|
14
|
+
a ="=?ISO-8859-1?B?WzE2NjQxN10gQmVrcuZmdGVsc2UgZnJhIFJlanNlZmViZXI=?="
|
15
|
+
b = TMail::Unquoter.unquote_and_convert_to(a, 'utf-8')
|
16
|
+
b.should == "[166417] Bekr\303\246ftelse fra Rejsefeber"
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should unquote without charset' do
|
20
|
+
a ="[166417]_Bekr=E6ftelse_fra_Rejsefeber"
|
21
|
+
b = TMail::Unquoter.unquote_and_convert_to(a, 'utf-8')
|
22
|
+
b.should == "[166417]_Bekr=E6ftelse_fra_Rejsefeber"
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should unqoute multiple' do
|
26
|
+
a ="=?utf-8?q?Re=3A_=5B12=5D_=23137=3A_Inkonsistente_verwendung_von_=22Hin?==?utf-8?b?enVmw7xnZW4i?="
|
27
|
+
b = TMail::Unquoter.unquote_and_convert_to(a, 'utf-8')
|
28
|
+
b.should == "Re: [12] #137: Inkonsistente verwendung von \"Hinzuf\303\274gen\""
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should unqoute in the middle' do
|
32
|
+
a ="Re: Photos =?ISO-8859-1?Q?Brosch=FCre_Rand?="
|
33
|
+
b = TMail::Unquoter.unquote_and_convert_to(a, 'utf-8')
|
34
|
+
b.should == "Re: Photos Brosch\303\274re Rand"
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should unqoute iso' do
|
38
|
+
a ="=?ISO-8859-1?Q?Brosch=FCre_Rand?="
|
39
|
+
b = TMail::Unquoter.unquote_and_convert_to(a, 'iso-8859-1')
|
40
|
+
expected = "Brosch\374re Rand"
|
41
|
+
expected.force_encoding 'iso-8859-1' if expected.respond_to?(:force_encoding)
|
42
|
+
b.should == expected
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'should quote multibyte chars' do
|
46
|
+
original = "\303\246 \303\270 and \303\245"
|
47
|
+
original.force_encoding('ASCII-8BIT') if original.respond_to?(:force_encoding)
|
48
|
+
|
49
|
+
result = execute_in_sandbox(<<-CODE)
|
50
|
+
$:.unshift(File.dirname(__FILE__) + "/../../../lib/")
|
51
|
+
$KCODE = 'u'
|
52
|
+
require 'jcode'
|
53
|
+
require 'mlist/util/quoting'
|
54
|
+
include MList::Util::Quoting
|
55
|
+
quoted_printable("UTF-8", #{original.inspect})
|
56
|
+
CODE
|
57
|
+
|
58
|
+
unquoted = TMail::Unquoter.unquote_and_convert_to(result, nil)
|
59
|
+
unquoted.should == original
|
60
|
+
end
|
61
|
+
|
62
|
+
# test an email that has been created using \r\n newlines, instead of
|
63
|
+
# \n newlines.
|
64
|
+
it 'should email quoted with 0d0a' do
|
65
|
+
mail = TMail::Mail.parse(IO.read("#{SPEC_ROOT}/fixtures/email/raw_email_quoted_with_0d0a"))
|
66
|
+
mail.body.should match(%r{Elapsed time})
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'should email with partially quoted subject' do
|
70
|
+
mail = TMail::Mail.parse(IO.read("#{SPEC_ROOT}/fixtures/email/raw_email_with_partially_quoted_subject"))
|
71
|
+
mail.subject.should == "Re: Test: \"\346\274\242\345\255\227\" mid \"\346\274\242\345\255\227\" tail"
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
# This whole thing *could* be much simpler, but I don't think Tempfile,
|
76
|
+
# popen and others exist on all platforms (like Windows).
|
77
|
+
def execute_in_sandbox(code)
|
78
|
+
test_name = "#{File.dirname(__FILE__)}/am-quoting-test.#{$$}.rb"
|
79
|
+
res_name = "#{File.dirname(__FILE__)}/am-quoting-test.#{$$}.out"
|
80
|
+
|
81
|
+
File.open(test_name, "w+") do |file|
|
82
|
+
file.write(<<-CODE)
|
83
|
+
block = Proc.new do
|
84
|
+
#{code}
|
85
|
+
end
|
86
|
+
puts block.call
|
87
|
+
CODE
|
88
|
+
end
|
89
|
+
|
90
|
+
system("ruby #{test_name} > #{res_name}") or raise "could not run test in sandbox"
|
91
|
+
File.read(res_name).chomp
|
92
|
+
ensure
|
93
|
+
File.delete(test_name) rescue nil
|
94
|
+
File.delete(res_name) rescue nil
|
95
|
+
end
|
96
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'spec'
|
3
|
+
require 'rr'
|
4
|
+
require 'ostruct'
|
5
|
+
|
6
|
+
Spec::Runner.configure do |config|
|
7
|
+
config.mock_with :rr
|
8
|
+
end
|
9
|
+
|
10
|
+
SPEC_ROOT = File.expand_path(File.dirname(__FILE__))
|
11
|
+
$LOAD_PATH.unshift(SPEC_ROOT + '/../lib')
|
12
|
+
Dir[SPEC_ROOT + '/matchers/*.rb'].each { |path| require path }
|
13
|
+
|
14
|
+
require 'active_record'
|
15
|
+
SQLITE_DATABASE = "#{SPEC_ROOT}/sqlite3.db"
|
16
|
+
ActiveRecord::Base.silence do
|
17
|
+
ActiveRecord::Base.configurations = {'test' => {
|
18
|
+
'adapter' => 'sqlite3',
|
19
|
+
'database' => SQLITE_DATABASE
|
20
|
+
}}
|
21
|
+
ActiveRecord::Base.establish_connection 'test'
|
22
|
+
load "#{SPEC_ROOT}/fixtures/schema.rb"
|
23
|
+
end
|
24
|
+
|
25
|
+
require 'dataset'
|
26
|
+
class Spec::Example::ExampleGroup
|
27
|
+
include Dataset
|
28
|
+
datasets_directory "#{SPEC_ROOT}/datasets"
|
29
|
+
end
|
30
|
+
|
31
|
+
# Fixture helpers
|
32
|
+
def email_fixtures_path(path)
|
33
|
+
File.join(SPEC_ROOT, 'fixtures/email', path)
|
34
|
+
end
|
35
|
+
|
36
|
+
def email_fixture(path)
|
37
|
+
File.read(email_fixtures_path(path))
|
38
|
+
end
|
39
|
+
|
40
|
+
def tmail_fixture(path, header_changes = {})
|
41
|
+
tmail = TMail::Mail.parse(email_fixture(path))
|
42
|
+
header_changes.each do |k,v|
|
43
|
+
tmail[k] = v
|
44
|
+
end
|
45
|
+
tmail
|
46
|
+
end
|
47
|
+
|
48
|
+
def html_fixtures_path(path)
|
49
|
+
File.join(SPEC_ROOT, 'fixtures/html', path)
|
50
|
+
end
|
51
|
+
|
52
|
+
def html_fixture(path)
|
53
|
+
File.read(html_fixtures_path(path))
|
54
|
+
end
|
55
|
+
|
56
|
+
def text_fixtures_path(path)
|
57
|
+
File.join(SPEC_ROOT, 'fixtures/text', path)
|
58
|
+
end
|
59
|
+
|
60
|
+
def text_fixture(path)
|
61
|
+
File.read(text_fixtures_path(path))
|
62
|
+
end
|
63
|
+
|
64
|
+
# To see the output of an email in your client, this will use sendmail to
|
65
|
+
# deliver the email to the given address. It shouldn't be sent to the
|
66
|
+
# addresses in to: cc: or bcc:, I hope.
|
67
|
+
#
|
68
|
+
def visualize_email(email, recipient_address)
|
69
|
+
tf = Tempfile.new('email_visualize')
|
70
|
+
tf.puts email.to_s
|
71
|
+
tf.close
|
72
|
+
`cat #{tf.path} | sendmail -t #{recipient_address}`
|
73
|
+
end
|
74
|
+
|
75
|
+
require 'mlist'
|
76
|
+
require 'mlist/email_server/fake'
|
metadata
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mlist
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.9
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Adam Williams
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-12-21 00:00:00 -05:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: A Ruby mailing list library designed to be integrated into other applications.
|
17
|
+
email: adam@thewilliams.ws
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README
|
24
|
+
- TODO
|
25
|
+
files:
|
26
|
+
- CHANGELOG
|
27
|
+
- README
|
28
|
+
- Rakefile
|
29
|
+
- TODO
|
30
|
+
- VERSION.yml
|
31
|
+
- lib/mlist.rb
|
32
|
+
- lib/mlist/email.rb
|
33
|
+
- lib/mlist/email_post.rb
|
34
|
+
- lib/mlist/email_server.rb
|
35
|
+
- lib/mlist/email_server/base.rb
|
36
|
+
- lib/mlist/email_server/default.rb
|
37
|
+
- lib/mlist/email_server/fake.rb
|
38
|
+
- lib/mlist/email_server/pop.rb
|
39
|
+
- lib/mlist/email_server/smtp.rb
|
40
|
+
- lib/mlist/email_subscriber.rb
|
41
|
+
- lib/mlist/list.rb
|
42
|
+
- lib/mlist/mail_list.rb
|
43
|
+
- lib/mlist/manager.rb
|
44
|
+
- lib/mlist/manager/database.rb
|
45
|
+
- lib/mlist/manager/notifier.rb
|
46
|
+
- lib/mlist/message.rb
|
47
|
+
- lib/mlist/server.rb
|
48
|
+
- lib/mlist/thread.rb
|
49
|
+
- lib/mlist/util.rb
|
50
|
+
- lib/mlist/util/email_helpers.rb
|
51
|
+
- lib/mlist/util/header_sanitizer.rb
|
52
|
+
- lib/mlist/util/quoting.rb
|
53
|
+
- lib/mlist/util/tmail_builder.rb
|
54
|
+
- lib/mlist/util/tmail_methods.rb
|
55
|
+
- lib/pop_ssl.rb
|
56
|
+
- rails/init.rb
|
57
|
+
has_rdoc: true
|
58
|
+
homepage: http://github.com/aiwilliams/mlist
|
59
|
+
licenses: []
|
60
|
+
|
61
|
+
post_install_message:
|
62
|
+
rdoc_options:
|
63
|
+
- --charset=UTF-8
|
64
|
+
require_paths:
|
65
|
+
- lib
|
66
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: "0"
|
71
|
+
version:
|
72
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: "0"
|
77
|
+
version:
|
78
|
+
requirements: []
|
79
|
+
|
80
|
+
rubyforge_project:
|
81
|
+
rubygems_version: 1.3.5
|
82
|
+
signing_key:
|
83
|
+
specification_version: 3
|
84
|
+
summary: A Ruby mailing list library designed to be integrated into other applications.
|
85
|
+
test_files:
|
86
|
+
- spec/fixtures/schema.rb
|
87
|
+
- spec/integration/date_formats_spec.rb
|
88
|
+
- spec/integration/mlist_spec.rb
|
89
|
+
- spec/integration/pop_email_server_spec.rb
|
90
|
+
- spec/integration/proof_spec.rb
|
91
|
+
- spec/matchers/equal_tmail.rb
|
92
|
+
- spec/matchers/have_address.rb
|
93
|
+
- spec/matchers/have_header.rb
|
94
|
+
- spec/models/email_post_spec.rb
|
95
|
+
- spec/models/email_server/base_spec.rb
|
96
|
+
- spec/models/email_spec.rb
|
97
|
+
- spec/models/mail_list_spec.rb
|
98
|
+
- spec/models/message_spec.rb
|
99
|
+
- spec/models/thread_spec.rb
|
100
|
+
- spec/models/util/email_helpers_spec.rb
|
101
|
+
- spec/models/util/header_sanitizer_spec.rb
|
102
|
+
- spec/models/util/quoting_spec.rb
|
103
|
+
- spec/spec_helper.rb
|