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,138 @@
|
|
1
|
+
module MList
|
2
|
+
module Util
|
3
|
+
|
4
|
+
module TMailReaders
|
5
|
+
def date
|
6
|
+
if date = tmail.header_string('date')
|
7
|
+
Time.parse(date)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def from_address
|
12
|
+
tmail.from.first.downcase
|
13
|
+
end
|
14
|
+
|
15
|
+
def html
|
16
|
+
case tmail.content_type
|
17
|
+
when 'text/html'
|
18
|
+
tmail.body.strip
|
19
|
+
when 'multipart/alternative'
|
20
|
+
html_part = tmail.parts.detect {|part| part.content_type == 'text/html'}
|
21
|
+
html_part.body.strip if html_part
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def identifier
|
26
|
+
remove_brackets(tmail.header_string('message-id'))
|
27
|
+
end
|
28
|
+
|
29
|
+
def mailer
|
30
|
+
tmail.header_string('x-mailer')
|
31
|
+
end
|
32
|
+
|
33
|
+
def text
|
34
|
+
text_content = ''
|
35
|
+
extract_text_content(tmail, text_content)
|
36
|
+
return text_content unless text_content.blank?
|
37
|
+
|
38
|
+
html_content = ''
|
39
|
+
extract_html_content(tmail, html_content)
|
40
|
+
return html_to_text(html_content) unless html_content.blank?
|
41
|
+
|
42
|
+
return nil
|
43
|
+
end
|
44
|
+
|
45
|
+
# Answers the first text/plain part it can find, the tmail itself if
|
46
|
+
# it's content type is text/plain.
|
47
|
+
#
|
48
|
+
def text_plain_part(part = tmail)
|
49
|
+
case part.content_type
|
50
|
+
when 'text/plain'
|
51
|
+
part
|
52
|
+
when 'multipart/alternative'
|
53
|
+
part.parts.detect {|part| text_plain_part(part)}
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
def extract_html_content(part, collector)
|
59
|
+
case part.content_type
|
60
|
+
when 'text/html'
|
61
|
+
collector << part.body.strip
|
62
|
+
when 'multipart/alternative', 'multipart/mixed', 'multipart/related'
|
63
|
+
part.parts.each {|part| extract_html_content(part, collector)}
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def extract_text_content(part, collector)
|
68
|
+
case part.content_type
|
69
|
+
when 'text/plain'
|
70
|
+
collector << part.body.strip
|
71
|
+
when 'multipart/alternative', 'multipart/mixed', 'multipart/related'
|
72
|
+
part.parts.each {|part| extract_text_content(part, collector)}
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
module TMailWriters
|
78
|
+
def charset
|
79
|
+
'utf-8'
|
80
|
+
end
|
81
|
+
|
82
|
+
def delete_header(name)
|
83
|
+
tmail[name] = nil
|
84
|
+
end
|
85
|
+
|
86
|
+
def headers=(updates)
|
87
|
+
updates.each do |k,v|
|
88
|
+
if TMail::Mail::ALLOW_MULTIPLE.include?(k.downcase)
|
89
|
+
prepend_header(k,v)
|
90
|
+
else
|
91
|
+
write_header(k,v)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# Add another value for the named header, it's position being earlier in
|
97
|
+
# the email than those that are already present. This will raise an error
|
98
|
+
# if the header does not allow multiple values according to
|
99
|
+
# TMail::Mail::ALLOW_MULTIPLE.
|
100
|
+
#
|
101
|
+
def prepend_header(name, value)
|
102
|
+
original = tmail[name] || []
|
103
|
+
tmail[name] = nil
|
104
|
+
tmail[name] = sanitize_header(charset, name, value)
|
105
|
+
tmail[name] = tmail[name] + original
|
106
|
+
end
|
107
|
+
|
108
|
+
def write_header(name, value)
|
109
|
+
tmail[name] = sanitize_header(charset, name, value)
|
110
|
+
end
|
111
|
+
|
112
|
+
def to=(recipient_addresses)
|
113
|
+
tmail.to = sanitize_header(charset, 'to', recipient_addresses)
|
114
|
+
end
|
115
|
+
|
116
|
+
def bcc=(recipient_addresses)
|
117
|
+
tmail.bcc = sanitize_header(charset, 'bcc', recipient_addresses)
|
118
|
+
end
|
119
|
+
|
120
|
+
def from=(from_address)
|
121
|
+
tmail.from = sanitize_header(charset, 'from', from_address)
|
122
|
+
end
|
123
|
+
|
124
|
+
def in_reply_to=(*values)
|
125
|
+
tmail.in_reply_to = sanitize_header(charset, 'in-reply-to', *values)
|
126
|
+
end
|
127
|
+
|
128
|
+
def mailer=(value)
|
129
|
+
write_header('x-mailer', value)
|
130
|
+
end
|
131
|
+
|
132
|
+
def message_id=(value)
|
133
|
+
tmail.message_id = sanitize_header(charset, 'message-id', value)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
end
|
data/lib/mlist/util.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'mlist/util/quoting'
|
2
|
+
require 'mlist/util/header_sanitizer'
|
3
|
+
require 'mlist/util/email_helpers'
|
4
|
+
require 'mlist/util/tmail_methods'
|
5
|
+
require 'mlist/util/tmail_builder'
|
6
|
+
|
7
|
+
module MList
|
8
|
+
module Util
|
9
|
+
mattr_accessor :default_header_sanitizers
|
10
|
+
self.default_header_sanitizers = HeaderSanitizerHash.new
|
11
|
+
end
|
12
|
+
end
|
data/lib/mlist.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
|
3
|
+
require 'uuid'
|
4
|
+
require 'tmail'
|
5
|
+
require 'hpricot'
|
6
|
+
require 'active_support'
|
7
|
+
require 'active_record'
|
8
|
+
|
9
|
+
require 'mlist/util'
|
10
|
+
require 'mlist/email'
|
11
|
+
require 'mlist/message'
|
12
|
+
require 'mlist/list'
|
13
|
+
require 'mlist/mail_list'
|
14
|
+
require 'mlist/email_post'
|
15
|
+
require 'mlist/email_server'
|
16
|
+
require 'mlist/email_subscriber'
|
17
|
+
require 'mlist/server'
|
18
|
+
require 'mlist/thread'
|
19
|
+
|
20
|
+
require 'mlist/manager'
|
21
|
+
|
22
|
+
module MList
|
23
|
+
mattr_reader :version
|
24
|
+
@@version = YAML.load_file(File.join(File.dirname(__FILE__), '..', "VERSION.yml"))
|
25
|
+
class << @@version
|
26
|
+
def to_s
|
27
|
+
@to_s ||= [self[:major], self[:minor], self[:patch]].join('.')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class DoubleDeliveryError < StandardError
|
32
|
+
def initialize(message)
|
33
|
+
super("A message should never be delivered more than once. An attempt was made to deliver this message:\n#{message.inspect}")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
Time::DATE_FORMATS[:mlist_reply_timestamp] = Date::DATE_FORMATS[:mlist_reply_timestamp] = lambda do |time|
|
39
|
+
time.strftime('%a, %b %d, %Y at %I:%M %p').sub(/0(\d,)/, '\1').sub(/0(\d:)/, '\1')
|
40
|
+
end
|
41
|
+
|
42
|
+
# In order to keep the inline images in email intact. Certainly a scary bit of
|
43
|
+
# hacking, but this is the solution out there on the internet.
|
44
|
+
TMail::HeaderField::FNAME_TO_CLASS.delete 'content-id'
|
45
|
+
|
46
|
+
TMail::Mail::ALLOW_MULTIPLE['x-beenthere'] = true
|