rmail 0.17

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. data/NEWS +309 -0
  2. data/NOTES +14 -0
  3. data/README +83 -0
  4. data/THANKS +25 -0
  5. data/TODO +112 -0
  6. data/guide/Intro.txt +122 -0
  7. data/guide/MIME.txt +6 -0
  8. data/guide/TableOfContents.txt +13 -0
  9. data/install.rb +1023 -0
  10. data/lib/rmail.rb +50 -0
  11. data/lib/rmail/address.rb +829 -0
  12. data/lib/rmail/header.rb +987 -0
  13. data/lib/rmail/mailbox.rb +62 -0
  14. data/lib/rmail/mailbox/mboxreader.rb +182 -0
  15. data/lib/rmail/message.rb +201 -0
  16. data/lib/rmail/parser.rb +412 -0
  17. data/lib/rmail/parser/multipart.rb +217 -0
  18. data/lib/rmail/parser/pushbackreader.rb +173 -0
  19. data/lib/rmail/serialize.rb +190 -0
  20. data/lib/rmail/utils.rb +59 -0
  21. data/rmail.gemspec +17 -0
  22. data/tests/addrgrammar.txt +113 -0
  23. data/tests/data/mbox.odd +4 -0
  24. data/tests/data/mbox.simple +8 -0
  25. data/tests/data/multipart/data.1 +5 -0
  26. data/tests/data/multipart/data.10 +1 -0
  27. data/tests/data/multipart/data.11 +9 -0
  28. data/tests/data/multipart/data.12 +9 -0
  29. data/tests/data/multipart/data.13 +3 -0
  30. data/tests/data/multipart/data.14 +3 -0
  31. data/tests/data/multipart/data.15 +3 -0
  32. data/tests/data/multipart/data.16 +3 -0
  33. data/tests/data/multipart/data.17 +0 -0
  34. data/tests/data/multipart/data.2 +5 -0
  35. data/tests/data/multipart/data.3 +2 -0
  36. data/tests/data/multipart/data.4 +3 -0
  37. data/tests/data/multipart/data.5 +1 -0
  38. data/tests/data/multipart/data.6 +2 -0
  39. data/tests/data/multipart/data.7 +3 -0
  40. data/tests/data/multipart/data.8 +5 -0
  41. data/tests/data/multipart/data.9 +4 -0
  42. data/tests/data/parser.badmime1 +4 -0
  43. data/tests/data/parser.badmime2 +6 -0
  44. data/tests/data/parser.nested-multipart +75 -0
  45. data/tests/data/parser.nested-simple +12 -0
  46. data/tests/data/parser.nested-simple2 +16 -0
  47. data/tests/data/parser.nested-simple3 +21 -0
  48. data/tests/data/parser.rfc822 +65 -0
  49. data/tests/data/parser.simple-mime +24 -0
  50. data/tests/data/parser/multipart.1 +8 -0
  51. data/tests/data/parser/multipart.10 +4 -0
  52. data/tests/data/parser/multipart.11 +12 -0
  53. data/tests/data/parser/multipart.12 +12 -0
  54. data/tests/data/parser/multipart.13 +6 -0
  55. data/tests/data/parser/multipart.14 +6 -0
  56. data/tests/data/parser/multipart.15 +6 -0
  57. data/tests/data/parser/multipart.16 +6 -0
  58. data/tests/data/parser/multipart.2 +8 -0
  59. data/tests/data/parser/multipart.3 +5 -0
  60. data/tests/data/parser/multipart.4 +6 -0
  61. data/tests/data/parser/multipart.5 +4 -0
  62. data/tests/data/parser/multipart.6 +5 -0
  63. data/tests/data/parser/multipart.7 +6 -0
  64. data/tests/data/parser/multipart.8 +8 -0
  65. data/tests/data/parser/multipart.9 +7 -0
  66. data/tests/data/transparency/absolute.1 +5 -0
  67. data/tests/data/transparency/absolute.2 +1 -0
  68. data/tests/data/transparency/absolute.3 +2 -0
  69. data/tests/data/transparency/absolute.4 +3 -0
  70. data/tests/data/transparency/absolute.5 +4 -0
  71. data/tests/data/transparency/absolute.6 +49 -0
  72. data/tests/data/transparency/message.1 +73 -0
  73. data/tests/data/transparency/message.2 +34 -0
  74. data/tests/data/transparency/message.3 +63 -0
  75. data/tests/data/transparency/message.4 +5 -0
  76. data/tests/data/transparency/message.5 +15 -0
  77. data/tests/data/transparency/message.6 +1185 -0
  78. data/tests/runtests.rb +35 -0
  79. data/tests/testaddress.rb +1192 -0
  80. data/tests/testbase.rb +207 -0
  81. data/tests/testheader.rb +1207 -0
  82. data/tests/testmailbox.rb +47 -0
  83. data/tests/testmboxreader.rb +161 -0
  84. data/tests/testmessage.rb +257 -0
  85. data/tests/testparser.rb +634 -0
  86. data/tests/testparsermultipart.rb +205 -0
  87. data/tests/testpushbackreader.rb +40 -0
  88. data/tests/testserialize.rb +264 -0
  89. data/tests/testtestbase.rb +112 -0
  90. data/tests/testtranspparency.rb +105 -0
  91. metadata +143 -0
@@ -0,0 +1,205 @@
1
+ #!/usr/bin/env ruby
2
+ #--
3
+ # Copyright (C) 2002, 2004 Matt Armstrong. All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # 1. Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ # 2. Redistributions in binary form must reproduce the above copyright
11
+ # notice, this list of conditions and the following disclaimer in the
12
+ # documentation and/or other materials provided with the distribution.
13
+ # 3. The name of the author may not be used to endorse or promote products
14
+ # derived from this software without specific prior written permission.
15
+ #
16
+ # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17
+ # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18
+ # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
19
+ # NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20
+ # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
21
+ # TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22
+ # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
+ #
27
+
28
+ require 'tests/testbase'
29
+ require 'rmail/parser/multipart'
30
+
31
+ class TestRMailParserMultipart < TestBase
32
+
33
+ # FIXME: TODO
34
+ # - test \n -vs- \r\n -vs \r end of line characters
35
+
36
+ def parse_multipart(filename, boundary, chunk_size, expected_results)
37
+ assembled = nil
38
+
39
+ data_as_file(filename) { |f|
40
+ parser = RMail::Parser::MultipartReader.new(f, boundary)
41
+ parser.chunk_size = chunk_size
42
+
43
+ results = []
44
+ loop {
45
+ chunk = parser.read(nil)
46
+ puts "test: got part #{chunk.inspect}" if $DEBUG
47
+ delimiter = parser.delimiter
48
+ puts "test: got delimiter #{delimiter.inspect}" if $DEBUG
49
+ if chunk
50
+ assembled ||= ''
51
+ assembled << chunk
52
+ end
53
+ if delimiter
54
+ assembled ||= ''
55
+ assembled << delimiter
56
+ end
57
+ results << [
58
+ chunk,
59
+ parser.preamble?,
60
+ parser.epilogue?,
61
+ delimiter
62
+ ]
63
+ unless parser.next_part
64
+ break
65
+ end
66
+ }
67
+ if expected_results != results
68
+ puts "\nfailure for chunks size #{chunk_size.to_s}"
69
+ pp expected_results
70
+ pp results
71
+ end
72
+ assert_equal(expected_results, results,
73
+ "\nfile #{filename}\nchunk_size #{chunk_size}\n")
74
+ }
75
+
76
+ filedata = data_as_file(filename) { |f|
77
+ f.read(nil)
78
+ }
79
+ filedata = nil if filedata.empty?
80
+
81
+ assert_equal(filedata, assembled,
82
+ "data loss while reassembling file data")
83
+ end
84
+
85
+ def for_all_chunk_sizes(filename, boundary, expected_results)
86
+ size = File.stat(data_filename(filename)).size
87
+ (size + 10).downto(1) { |chunk_size|
88
+ parse_multipart(filename, boundary, chunk_size, expected_results)
89
+ }
90
+ end
91
+
92
+ def test_multipart_data_01
93
+ for_all_chunk_sizes('multipart/data.1', 'aa',
94
+ [ [ "preamble", true, false, "\n--aa\n" ],
95
+ [ "part1", false, false, "\n--aa--\n" ],
96
+ [ "epilogue\n", false, true, nil ] ])
97
+ end
98
+ def test_multipart_data_02
99
+ for_all_chunk_sizes('multipart/data.2', 'aa',
100
+ [ [ nil, true, false, "\n--aa\n" ],
101
+ [ nil, false, false, "\n--aa--\n" ],
102
+ [ "\n", false, true, nil ] ])
103
+ end
104
+ def test_multipart_data_03
105
+ for_all_chunk_sizes('multipart/data.3', 'aa',
106
+ [ [ nil, true, false, "--aa\n" ],
107
+ [ nil, false, false, "--aa--\n" ],
108
+ [ "", false, true, nil ] ])
109
+ end
110
+ def test_multipart_data_04
111
+ for_all_chunk_sizes('multipart/data.4', 'aa',
112
+ [ [ "preamble", true, false, "\n--aa--\n" ],
113
+ [ "epilogue\n", false, true, nil ] ])
114
+ end
115
+ def test_multipart_data_05
116
+ for_all_chunk_sizes('multipart/data.5', 'aa',
117
+ [ [ nil, true, false, "--aa--\n" ],
118
+ [ "", false, true, nil ] ])
119
+ end
120
+ def test_multipart_data_06
121
+ for_all_chunk_sizes('multipart/data.6', 'aa',
122
+ [ [ nil, true, false, "\n--aa--\n" ],
123
+ [ "", false, true, nil ] ])
124
+ end
125
+ def test_multipart_data_07
126
+ for_all_chunk_sizes('multipart/data.7', 'aa',
127
+ [ [ "preamble\n", true, false, "\n--aa--\n" ],
128
+ [ "", false, true, nil ] ])
129
+ end
130
+ def test_multipart_data_08
131
+ for_all_chunk_sizes('multipart/data.8', 'aa',
132
+ [ [ "preamble", true, false, "\n--aa\n" ],
133
+ [ "part1", false, false, "\n--aa--\n" ],
134
+ [ "epilogue", false, true, nil ] ])
135
+ end
136
+ def test_multipart_data_09
137
+ for_all_chunk_sizes('multipart/data.9', 'aa',
138
+ [ [ nil, true, false, "\n--aa\n" ],
139
+ [ nil, false, false, "\n--aa--" ],
140
+ [ "", false, true, nil ] ])
141
+ end
142
+ def test_multipart_data_10
143
+ for_all_chunk_sizes('multipart/data.10', 'aa',
144
+ [ [ nil, true, false, "--aa--" ],
145
+ [ "", false, true, nil ] ])
146
+ end
147
+ def test_multipart_data_11
148
+ for_all_chunk_sizes('multipart/data.11', 'aa',
149
+ [ [ "preamble", true, false, "\n--aa\t\n" ],
150
+ [ "part1", false, false, "\n--aa \n" ],
151
+ [ "part2", false, false, "\n--aa \t \t\n" ],
152
+ [ "part3", false, false, "\n--aa-- \n" ],
153
+ [ "epilogue\n", false, true, nil ] ])
154
+ end
155
+ def test_multipart_data_12
156
+ # The following from RFC2046 indicates that a delimiter existing
157
+ # as the prefix of a line is sufficient for the line to be
158
+ # considered a delimiter -- even if there is stuff after the
159
+ # boundary:
160
+ #
161
+ # NOTE TO IMPLEMENTORS: Boundary string comparisons must
162
+ # compare the boundary value with the beginning of each
163
+ # candidate line. An exact match of the entire candidate line
164
+ # is not required; it is sufficient that the boundary appear in
165
+ # its entirety following the CRLF.
166
+ #
167
+ # However, messages in the field do not seem to comply with this
168
+ # (namely, Eudora), so we parse more strictly.
169
+ for_all_chunk_sizes('multipart/data.12', 'aa',
170
+ [[ "preamble\n--aaZ\npart1\n--aa notignored\npart2\n--aa \t \tnotignored\npart3\n--aa--notignored\nepilogue\n",
171
+ true,
172
+ false,
173
+ nil ]])
174
+ end
175
+ def test_multipart_data_13
176
+ for_all_chunk_sizes('multipart/data.13', 'aa',
177
+ [ [ "preamble", true, false, "\n--aa\n" ],
178
+ [ "part1\n", false, false, nil ] ])
179
+ end
180
+ def test_multipart_data_14
181
+ for_all_chunk_sizes('multipart/data.14', 'aa',
182
+ [ [ "preamble", true, false, "\n--aa\n" ],
183
+ [ "part1", false, false, nil ] ])
184
+ end
185
+ def test_multipart_data_15
186
+ for_all_chunk_sizes('multipart/data.15', 'aa',
187
+ [ [ "preamble\nline1\nline2\n", true, false, nil ] ])
188
+ end
189
+ def test_multipart_data_16
190
+ for_all_chunk_sizes('multipart/data.16', 'aa',
191
+ [ [ "preamble\nline1\nline2", true, false, nil ] ])
192
+ end
193
+ def test_multipart_data_17
194
+ for_all_chunk_sizes('multipart/data.17', 'aa',
195
+ [ [ nil, true, false, nil ] ])
196
+ end
197
+
198
+ def test_s_new
199
+ data_as_file('multipart/data.1') { |f|
200
+ p = RMail::Parser::MultipartReader.new(f, "foo")
201
+ assert_kind_of(RMail::Parser::MultipartReader, p)
202
+ }
203
+ end
204
+
205
+ end
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env ruby
2
+ #--
3
+ # Copyright (c) 2002 Matt Armstrong. All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # 1. Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ # 2. Redistributions in binary form must reproduce the above copyright
11
+ # notice, this list of conditions and the following disclaimer in the
12
+ # documentation and/or other materials provided with the distribution.
13
+ # 3. The name of the author may not be used to endorse or promote products
14
+ # derived from this software without specific prior written permission.
15
+ #
16
+ # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17
+ # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18
+ # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
19
+ # NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20
+ # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
21
+ # TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22
+ # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
+ #
27
+
28
+ require 'tests/testbase'
29
+ require 'rmail/mailbox/mboxreader'
30
+
31
+ class TextRMailParserPushbackReader < TestBase
32
+
33
+ def test_pushback
34
+ reader = RMail::Parser::PushbackReader.new("")
35
+ assert_exception(RMail::Parser::Error) {
36
+ reader.pushback("hi bob")
37
+ }
38
+ end
39
+
40
+ end
@@ -0,0 +1,264 @@
1
+ #!/usr/bin/env ruby
2
+ #--
3
+ # Copyright (C) 2002, 2003 Matt Armstrong. All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # 1. Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ # 2. Redistributions in binary form must reproduce the above copyright
11
+ # notice, this list of conditions and the following disclaimer in the
12
+ # documentation and/or other materials provided with the distribution.
13
+ # 3. The name of the author may not be used to endorse or promote products
14
+ # derived from this software without specific prior written permission.
15
+ #
16
+ # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17
+ # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18
+ # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
19
+ # NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20
+ # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
21
+ # TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22
+ # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
+ #
27
+
28
+ require 'tests/testbase'
29
+ require 'rmail/serialize'
30
+ require 'rmail/message'
31
+
32
+ class TestRMailSerialize < TestBase
33
+ def test_serialize_empty
34
+ s = RMail::Serialize.new('').serialize(RMail::Message.new)
35
+ assert_equal("", s)
36
+ end
37
+
38
+ def test_serialize_basic
39
+ m = RMail::Message.new
40
+ m.header['to'] = "bob@example.net"
41
+ m.header['from'] = "sally@example.net"
42
+ m.body = "This is the body."
43
+ s = RMail::Serialize.new('').serialize(m)
44
+ assert_equal(%q{to: bob@example.net
45
+ from: sally@example.net
46
+
47
+ This is the body.
48
+ },
49
+ s)
50
+ end
51
+
52
+ def test_serialize_s_write
53
+ m = RMail::Message.new
54
+ m.header['to'] = "bob@example.net"
55
+ m.header['from'] = "sally@example.net"
56
+ m.body = "This is the body."
57
+ s = RMail::Serialize.write('', m)
58
+ assert_equal(%q{to: bob@example.net
59
+ from: sally@example.net
60
+
61
+ This is the body.
62
+ },
63
+ s)
64
+ end
65
+
66
+ def test_serialize_boundary_generation
67
+ m = RMail::Message.new
68
+ m.add_part(RMail::Message.new)
69
+ m.add_part(RMail::Message.new)
70
+
71
+ m.part(0).body = "body0\n"
72
+ m.part(1).body = "body1\n"
73
+
74
+ m.to_s
75
+
76
+ assert_match(/^=-\d+-\d+-\d+-\d+-\d+-=$/,
77
+ m.header.param('content-type', 'boundary'))
78
+ end
79
+
80
+ def test_serialize_boundary_override
81
+ m = RMail::Message.new
82
+ m.add_part(RMail::Message.new)
83
+ m.header.set_boundary("a")
84
+
85
+ m.part(0).add_part(RMail::Message.new)
86
+ m.part(0).header.set_boundary("a")
87
+
88
+ m.to_s
89
+
90
+ assert_match(/^=-\d+-\d+-\d+-\d+-\d+-=$/,
91
+ m.part(0).header.param('content-type', 'boundary'))
92
+ assert_equal("a", m.header.param('content-type', 'boundary'))
93
+ end
94
+
95
+ def test_serialize_multipart_basic
96
+ m = RMail::Message.new
97
+ m.header['to'] = "bob@example.net"
98
+ m.header['from'] = "sally@example.net"
99
+ m.header.set_boundary('=-=-=')
100
+ part = RMail::Message.new
101
+ part.body = "This is a text/plain part."
102
+ m.add_part(part)
103
+ part = RMail::Message.new
104
+ part.body = "This is a whacked out wacky part.\n"
105
+ part.header['Content-Disposition'] = 'inline'
106
+ m.add_part(part)
107
+ part = RMail::Message.new
108
+ part.body = "This is another whacked out wacky part.\n\n"
109
+ part.header['Content-Disposition'] = 'inline'
110
+ m.add_part(part)
111
+ s = RMail::Serialize.new('').serialize(m)
112
+ assert_equal(%q{to: bob@example.net
113
+ from: sally@example.net
114
+ Content-Type: multipart/mixed; boundary="=-=-="
115
+ MIME-Version: 1.0
116
+
117
+
118
+ --=-=-=
119
+
120
+ This is a text/plain part.
121
+ --=-=-=
122
+ Content-Disposition: inline
123
+
124
+ This is a whacked out wacky part.
125
+
126
+ --=-=-=
127
+ Content-Disposition: inline
128
+
129
+ This is another whacked out wacky part.
130
+
131
+
132
+ --=-=-=--
133
+ },
134
+ s)
135
+ end
136
+
137
+ def test_serialize_multipart_nested
138
+ m = RMail::Message.new
139
+ m.header.set_boundary('=-=-=')
140
+
141
+ part = RMail::Message.new
142
+ m.add_part(part)
143
+ m.part(0).header.set_boundary('==-=-=')
144
+
145
+ part = RMail::Message.new
146
+ m.part(0).add_part(RMail::Message.new)
147
+
148
+ part = RMail::Message.new
149
+ m.part(0).add_part(RMail::Message.new)
150
+
151
+ s = RMail::Serialize.new('').serialize(m)
152
+ assert_equal(%q{Content-Type: multipart/mixed; boundary="=-=-="
153
+ MIME-Version: 1.0
154
+
155
+
156
+ --=-=-=
157
+ Content-Type: multipart/mixed; boundary="==-=-="
158
+
159
+
160
+ --==-=-=
161
+
162
+ --==-=-=
163
+
164
+ --==-=-=--
165
+
166
+ --=-=-=--
167
+ },
168
+ s)
169
+ end
170
+
171
+ def test_serialize_multipart_epilogue_preamble
172
+ m = RMail::Message.new
173
+ m.preamble = %q{This is a multipart message in MIME format.
174
+ You are not using a message reader that understands MIME format.
175
+ Sucks to be you.}
176
+ m.epilogue = %q{This is the end of a multipart message in MIME format.
177
+ You are not using a message reader that understands MIME format.
178
+ Sucks to be you.
179
+ }
180
+ m.header['to'] = "bob@example.net"
181
+ m.header['from'] = "sally@example.net"
182
+ m.header.set_boundary('=-=-=')
183
+
184
+ part = RMail::Message.new
185
+ part.preamble = "SHOULD NOT SHOW UP"
186
+ part.body = "This is the body of the first part."
187
+ part.epilogue = "SHOULD NOT SHOW UP"
188
+ m.add_part(part)
189
+
190
+ part = RMail::Message.new
191
+ part.body = "This is the body of the second part.\n"
192
+ part.header['Content-Disposition'] = 'inline'
193
+ m.add_part(part)
194
+
195
+ part = RMail::Message.new
196
+ part.body = "This is the body of the third part.\n\n"
197
+ part.header['Content-Disposition'] = "inline\n"
198
+ part.header['X-Silly-Header'] = "silly value\n"
199
+ m.add_part(part)
200
+
201
+ s = RMail::Serialize.new('').serialize(m)
202
+ assert_equal(%q{to: bob@example.net
203
+ from: sally@example.net
204
+ Content-Type: multipart/mixed; boundary="=-=-="
205
+ MIME-Version: 1.0
206
+
207
+ This is a multipart message in MIME format.
208
+ You are not using a message reader that understands MIME format.
209
+ Sucks to be you.
210
+ --=-=-=
211
+
212
+ This is the body of the first part.
213
+ --=-=-=
214
+ Content-Disposition: inline
215
+
216
+ This is the body of the second part.
217
+
218
+ --=-=-=
219
+ Content-Disposition: inline
220
+ X-Silly-Header: silly value
221
+
222
+ This is the body of the third part.
223
+
224
+
225
+ --=-=-=--
226
+ This is the end of a multipart message in MIME format.
227
+ You are not using a message reader that understands MIME format.
228
+ Sucks to be you.
229
+ },
230
+ s)
231
+
232
+ m.epilogue = "foo\n\n"
233
+ s = RMail::Serialize.new('').serialize(m)
234
+ assert_equal(%q{to: bob@example.net
235
+ from: sally@example.net
236
+ Content-Type: multipart/mixed; boundary="=-=-="
237
+ MIME-Version: 1.0
238
+
239
+ This is a multipart message in MIME format.
240
+ You are not using a message reader that understands MIME format.
241
+ Sucks to be you.
242
+ --=-=-=
243
+
244
+ This is the body of the first part.
245
+ --=-=-=
246
+ Content-Disposition: inline
247
+
248
+ This is the body of the second part.
249
+
250
+ --=-=-=
251
+ Content-Disposition: inline
252
+ X-Silly-Header: silly value
253
+
254
+ This is the body of the third part.
255
+
256
+
257
+ --=-=-=--
258
+ foo
259
+
260
+ },
261
+ s)
262
+ end
263
+
264
+ end