rmail 0.17

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.
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