1<html><head><title>The README file: Tcl MIME</title>
2<meta http-equiv="Expires" content="Wed, 23 Feb 2000 04:36:30 +0000">
3<STYLE type='text/css'>
4 .title { color: #990000; font-size: 22px; line-height: 22px; font-weight: bold; text-align: right;
5 font-family: helvetica, arial, sans-serif }
6 .filename { color: #666666; font-size: 18px; line-height: 28px; font-weight: bold; text-align: right;
7 font-family: helvetica, arial, sans-serif }
8 p.copyright { color: #000000; font-size: 10px;
9 font-family: verdana, charcoal, helvetica, arial, sans-serif }
10 p { margin-left: 2em; margin-right: 2em; }
11 ol { margin-left: 2em; margin-right: 2em; }
12 ul.text { margin-left: 2em; margin-right: 2em; }
13 pre { margin-left: 3em; color: #333333 }
14 ul.toc { color: #000000; line-height: 16px;
15 font-family: verdana, charcoal, helvetica, arial, sans-serif }
16 H3 { color: #333333; font-size: 16px; line-height: 16px; font-family: helvetica, arial, sans-serif }
17 H4 { color: #000000; font-size: 14px; font-family: helvetica, arial, sans-serif }
18 TD.header { color: #ffffff; font-size: 10px; font-family: arial, helvetica, san-serif; valign: top }
19 TD.author-text { color: #000000; font-size: 10px;
20 font-family: verdana, charcoal, helvetica, arial, sans-serif }
21 TD.author { color: #000000; font-weight: bold; margin-left: 4em; font-size: 10px; font-family: verdana, charcoal, helvetica, arial, sans-serif }
22 A:link { color: #990000; font-size: 10px; text-transform: uppercase; font-weight: bold;
23 font-family: MS Sans Serif, verdana, charcoal, helvetica, arial, sans-serif }
24 A:visited { color: #333333; font-weight: bold; font-size: 10px; text-transform: uppercase;
25 font-family: MS Sans Serif, verdana, charcoal, helvetica, arial, sans-serif }
26 A:name { color: #333333; font-weight: bold; font-size: 10px; text-transform: uppercase;
27 font-family: MS Sans Serif, verdana, charcoal, helvetica, arial, sans-serif }
28 .link2 { color:#ffffff; font-weight: bold; text-decoration: none;
29 font-family: monaco, charcoal, geneva, MS Sans Serif, helvetica, monotype, verdana, sans-serif;
30 font-size: 9px }
31 .RFC { color:#666666; font-weight: bold; text-decoration: none;
32 font-family: monaco, charcoal, geneva, MS Sans Serif, helvetica, monotype, verdana, sans-serif;
33 font-size: 9px }
34 .hotText { color:#ffffff; font-weight: normal; text-decoration: none;
35 font-family: charcoal, monaco, geneva, MS Sans Serif, helvetica, monotype, verdana, sans-serif;
36 font-size: 9px }
37</style>
38</head>
39<body bgcolor="#ffffff"alink="#000000" vlink="#666666" link="#990000">
40<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b> TOC </b></font></a><br></td></tr></table>
41<table width="66%" border="0" cellpadding="0" cellspacing="0"><tr><td><table width="100%" border="0" cellpadding="2" cellspacing="1">
42<tr valign="top"><td width="33%" bgcolor="#666666" class="header">The README file</td><td width="33%" bgcolor="#666666" class="header">M.T. Rose</td></tr>
43<tr valign="top"><td width="33%" bgcolor="#666666" class="header"> </td><td width="33%" bgcolor="#666666" class="header">Dover Beach Consulting, Inc.</td></tr>
44<tr valign="top"><td width="33%" bgcolor="#666666" class="header"> </td><td width="33%" bgcolor="#666666" class="header">February 22, 2000</td></tr>
45</table></td></tr></table>
46<div align="right"><font face="monaco, MS Sans Serif" color="#990000" size="+3"><b><br><span class="title">Tcl MIME</span></b></font></div>
47<font face="verdana, helvetica, arial, sans-serif" size="2">
48
49<h3>Abstract</h3>
50
51<p>
52Tcl MIME generates and parses MIME body parts.
53</p>
54<a name="toc"><br><hr size="1" shade="0"></a>
55<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b> TOC </b></font></a><br></td></tr></table>
56<h3>Table of Contents</h3>
57<ul compact class="toc">
58<b><a href="#anchor1">1.</a>
59SYNOPSIS<br></b>
60<b><a href="#anchor2">1.1</a>
61Requirements<br></b>
62<b><a href="#anchor3">1.2</a>
63Copyrights<br></b>
64<b><a href="#anchor4">2.</a>
65SYNTAX<br></b>
66<b><a href="#anchor5">3.</a>
67SEMANTICS<br></b>
68<b><a href="#mime_initialize">3.1</a>
69mime::initialize<br></b>
70<b><a href="#mime_finalize">3.2</a>
71mime::finalize<br></b>
72<b><a href="#mime_getproperty">3.3</a>
73mime::getproperty<br></b>
74<b><a href="#mime_getheader">3.4</a>
75mime::getheader<br></b>
76<b><a href="#mime_setheader">3.5</a>
77mime::setheader<br></b>
78<b><a href="#mime_getbody">3.6</a>
79mime::getbody<br></b>
80<b><a href="#mime_copymessage">3.7</a>
81mime::copymessage<br></b>
82<b><a href="#mime_buildmessage">3.7</a>
83mime::buildmessage<br></b>
84<b><a href="#smtp_sendmessage">3.8</a>
85smtp::sendmessage<br></b>
86<b><a href="#mime_parseaddress">3.9</a>
87mime::parseaddress<br></b>
88<b><a href="#mime_parsedatetime">3.10</a>
89mime::parsedatetime<br></b>
90<b><a href="#mime_mapencoding">3.10</a>
91mime::mapencoding<br></b>
92<b><a href="#mime_reversemapencoding">3.10</a>
93mime::reversemapencoding<br></b>
94
95<b><a href="#anchor6">4.</a>
96EXAMPLES<br></b>
97<b><a href="#rfc.references">§</a>
98References<br></b>
99<b><a href="#rfc.authors">§</a>
100Author's Address<br></b>
101<b><a href="#anchor7">A.</a>
102TODO List<br></b>
103<b><a href="#anchor8">B.</a>
104Acknowledgements<br></b>
105</ul>
106<br clear="all">
107
108<a name="anchor1"><br><hr size="1" shade="0"></a>
109<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b> TOC </b></font></a><br></td></tr></table>
110<h3>1. SYNOPSIS</h3>
111</font><pre>
112 package provide mime 1.2
113 package provide smtp 1.2
114</pre><font face="verdana, helvetica, arial, sans-serif" size="2">
115
116<p>
117Tcl MIME is an implementation of a Tcl package that generates and
118parses <a href="#RFC2045">MIME</a>[1] body parts.
119</p>
120
121<p>
122Each MIME part consists of a header
123(zero or more key/value pairs),
124an empty line,
125and a structured body.
126A MIME part is either a "leaf" or has (zero or more) subordinates.
127</p>
128
129<p>
130MIME defines four keys that may appear in the headers:
131
132<blockquote class="text"><dl>
133
134<dt> Content-Type:</dt>
135<dd>
136describes the data contained in the body
137("the content");
138</dd>
139
140<dt> Content-Transfer-Encoding:</dt>
141<dd>
142describes how the content is
143encoded for transmission in an ASCII stream;
144</dd>
145
146<dt> Content-Description:</dt>
147<dd>
148a textual description of the
149content; and,
150</dd>
151
152<dt> Content-ID:</dt>
153<dd>
154a globally-unique identifier for the
155content.
156</dd>
157
158</dl></blockquote>
159
160</p>
161
162<p>
163Consult <a href="#RFC2046">[2]</a> for a list of standard content types.
164Further,
165consult <a href="#RFC822">[3]</a> for a list of several other header keys
166(e.g., "To", "cc", etc.)
167</p>
168
169<p>
170A simple example might be:
171</p>
172</font><pre>
173 Date: Sun, 04 July 1999 10:38:25 -0600
174 From: Marshall Rose <mrose@dbc.mtview.ca.us>
175 To: Andreas Kupries <a.kupries@westend.com>
176 cc: dnew@messagemedia.com (Darren New)
177 MIME-Version: 1.0
178 Content-Type: text/plain; charset="us-ascii"
179 Content-Description: a simple example
180 Content-ID: <4294407315.931384918.1@dbc.mtview.ca.us>
181
182 Here is the body. In this case, simply plain text.
183</pre><font face="verdana, helvetica, arial, sans-serif" size="2">
184
185<p>
186In addition to an implementation of the mime package,
187Tcl MIME includes an implementation of the smtp package.
188</p>
189
190<h4><a name="anchor2">1.1</a> Requirements</h4>
191
192<p>
193This package requires:
194
195<ul class="text">
196
197<li>
198<a href="http://www.scriptics.com/software/8.1.html">Tcl/Tk version 8.0.3</a>
199or later
200</li>
201</ul>
202</p>
203<p>
204In addition, this package requires one of the following:
205
206<ul class="text">
207<li>
208<a href="http://www.oche.de/~akupries/soft/trf/">Trf version 2.0p5</a> or later
209</li>
210<li>
211<a href="http://dev.ajubasolutions.com/software/tcllib/">base 64
212version 2.0</a> or later (included with tcllib)
213</li>
214</ul>
215</p>
216<p>
217If it is available, Trf will be used to provide better performance;
218if not, Tcl-only equivalent functions, based on the base64 package, are used.
219</p>
220
221<h4><a name="anchor3">1.2</a> Copyrights</h4>
222
223<p>
224(c) 1999-2000 Marshall T. Rose
225</p>
226
227<p>
228Hold harmless the author, and any lawful use is allowed.
229</p>
230
231<a name="anchor4"><br><hr size="1" shade="0"></a>
232<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b> TOC </b></font></a><br></td></tr></table>
233<h3>2. SYNTAX</h3>
234
235<p>
236<a href="#mime_initialize">mime::initialize</a>
237returns a token.
238Parameters:
239</p>
240</font><pre> ?-canonical type/subtype
241 ?-param {key value}?...
242 ?-encoding value?
243 ?-header {key value}?... ?
244 (-file name | -string value | -parts {token1 ... tokenN})
245</pre><font face="verdana, helvetica, arial, sans-serif" size="2">
246
247<p>
248<a href="#mime_finalize">mime::finalize</a> returns
249an empty string.
250Parameters:
251</p>
252</font><pre> token ?-subordinates "all" | "dynamic" | "none"?
253</pre><font face="verdana, helvetica, arial, sans-serif" size="2">
254
255<p>
256<a href="#mime_getproperty">mime::getproperty</a>
257returns a string or a list of strings.
258Parameters:
259</p>
260</font><pre> token ?property | -names?
261</pre><font face="verdana, helvetica, arial, sans-serif" size="2">
262
263<p>
264<a href="#mime_getheader">mime::getheader</a> returns
265a list of strings.
266Parameters:
267</p>
268</font><pre> token ?key | -names?
269</pre><font face="verdana, helvetica, arial, sans-serif" size="2">
270
271<p>
272<a href="#mime_setheader">mime::setheader</a> returns
273a list of strings.
274Parameters:
275</p>
276</font><pre> token key value ?-mode "write" | "append" | "delete"?
277</pre><font face="verdana, helvetica, arial, sans-serif" size="2">
278
279<p>
280<a href="#mime_getbody">mime::getbody</a> returns a string.
281Parameters:
282</p>
283</font><pre> ?-command callback ?-blocksize octets? ?
284</pre><font face="verdana, helvetica, arial, sans-serif" size="2">
285
286<p>
287<a href="#mime_copymessage">mime::copymessage</a>
288returns an empty string.
289Parameters:
290</p>
291</font><pre> token channel
292</pre><font face="verdana, helvetica, arial, sans-serif" size="2">
293
294<p>
295<a href="#mime_buildmessage">mime::buildmessage</a>
296returns a string.
297Parameters:
298</p>
299</font><pre> token
300</pre><font face="verdana, helvetica, arial, sans-serif" size="2">
301
302<p>
303<a href="#smtp_sendmessage">smtp::sendmessage</a>
304returns a list.
305Parameters:
306</p>
307</font><pre> token ?-servers list? ?-ports list?
308 ?-queue boolean? ?-atleastone boolean?
309 ?-originator string? ?-recipients string?
310 ?-header {key value}?...
311</pre><font face="verdana, helvetica, arial, sans-serif" size="2">
312
313<p>
314<a href="#mime_parseaddress">mime::parseaddress</a>
315returns a list of serialized arrays.
316Parameters:
317</p>
318</font><pre> string
319</pre><font face="verdana, helvetica, arial, sans-serif" size="2">
320
321<p>
322<a href="#mime_parsedatetime">mime::parsedatetime</a>
323returns a string.
324Parameters:
325</p>
326</font><pre> [string | -now] property
327</pre><font face="verdana, helvetica, arial, sans-serif" size="2">
328
329<p>
330<a href="#mime_mapencoding">mime::mapencoding</a>
331returns a string.
332Parameters:
333</p>
334</font><pre> encoding_name
335</pre><font face="verdana, helvetica, arial, sans-serif" size="2">
336
337<p>
338<a href="#mime_reversemapencoding">mime::reversemapencoding</a>
339returns a string.
340Parameters:
341</p>
342</font><pre> mime_charset
343</pre><font face="verdana, helvetica, arial, sans-serif" size="2">
344
345<a name="anchor5"><br><hr size="1" shade="0"></a>
346<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b> TOC </b></font></a><br></td></tr></table>
347<h3>3. SEMANTICS</h3>
348
349<h4><a name="mime_initialize">3.1</a> mime::initialize</h4>
350
351<p>
352mime::initialize creates a MIME part:
353
354<ul class="text">
355
356<li>
357If the -canonical option is present,
358then the body is in canonical (raw) form and is found by consulting
359either the -file, -string, or -part option.
360<br>
361<br>
362
363In addition,
364both the -param and -header options may occur zero or more times to
365specify "Content-Type" parameters (e.g., "charset")
366and header keyword/values (e.g., "Content-Disposition"),
367respectively.
368<br>
369<br>
370
371Also, -encoding, if present,
372specifies the "Content-Transfer-Encoding" when copying the body.
373</li>
374
375<li>
376If the -canonical option is not present,
377then the MIME part contained in either the -file or the -string option
378is parsed,
379dynamically generating subordinates as appropriate.
380</li>
381
382</ul>
383
384</p>
385
386<h4><a name="mime_finalize">3.2</a> mime::finalize</h4>
387
388<p>
389mime::finalize destroys a MIME part.
390</p>
391
392<p>
393If the -subordinates option is present,
394it specifies which subordinates should also be destroyed.
395The default value is "dynamic".
396</p>
397
398<h4><a name="mime_getproperty">3.3</a> mime::getproperty</h4>
399
400<p>
401mime::getproperty returns the properties of a MIME part.
402</p>
403
404<p>
405The properties are:
406</p>
407</font><pre>
408 property value
409 ======== =====
410 content the type/subtype describing the content
411 encoding the "Content-Transfer-Encoding"
412 params a list of "Content-Type" parameters
413 parts a list of tokens for the part's subordinates
414 size the approximate size of the content (unencoded)
415</pre><font face="verdana, helvetica, arial, sans-serif" size="2">
416
417<p>
418The "parts" property is present only if the MIME part has
419subordinates.
420</p>
421
422<p>
423If mime::getproperty is invoked with the name of a specific property,
424then the corresponding value is returned;
425instead,
426if -names is specified,
427a list of all properties is returned;
428otherwise,
429a serialized array of properties and values is returned.
430</p>
431
432<h4><a name="mime_getheader">3.4</a> mime::getheader</h4>
433
434<p>
435mime::getheader returns the header of a MIME part.
436</p>
437
438<p>
439A header consists of zero or more key/value pairs.
440Each value is a list containing one or more strings.
441</p>
442
443<p>
444If mime::getheader is invoked with the name of a specific key,
445then a list containing the corresponding value(s) is returned;
446instead,
447if -names is specified,
448a list of all keys is returned;
449otherwise,
450a serialized array of keys and values is returned.
451Note that when a key is specified (e.g., "Subject"),
452the list returned usually contains exactly one string;
453however,
454some keys (e.g., "Received") often occur more than once in the header,
455accordingly the list returned usually contains more than one string.
456</p>
457
458<h4><a name="mime_setheader">3.5</a> mime::setheader</h4>
459
460<p>
461mime::setheader writes, appends to, or deletes the value associated
462with a key in the header.
463</p>
464
465<p>
466The value for -mode is one of:
467
468<blockquote class="text"><dl>
469
470<dt> write:</dt>
471<dd>
472 the key/value is either created or
473overwritten (the default);
474</dd>
475
476<dt> append:</dt>
477<dd>
478 a new value is appended for the key
479(creating it as necessary); or,
480</dd>
481
482<dt> delete:</dt>
483<dd>
484 all values associated with the key are removed
485(the "value" parameter is ignored).
486</dd>
487
488</dl></blockquote>
489
490</p>
491
492<p>
493Regardless,
494mime::setheader returns the previous value associated with the key.
495</p>
496
497<h4><a name="mime_getbody">3.6</a> mime::getbody</h4>
498
499<p>
500mime::getbody returns the body of a leaf MIME part in canonical form.
501</p>
502
503<p>
504If the -command option is present,
505then it is repeatedly invoked with a fragment of the body as this:
506</p>
507</font><pre>
508 uplevel #0 $callback [list "data" $fragment]
509</pre><font face="verdana, helvetica, arial, sans-serif" size="2">
510
511<p>
512(The -blocksize option,
513if present,
514specifies the maximum size of each fragment passed to the
515callback.)
516</p>
517
518<p>
519When the end of the body is reached,
520the callback is invoked as:
521</p>
522</font><pre>
523 uplevel #0 $callback "end"
524</pre><font face="verdana, helvetica, arial, sans-serif" size="2">
525
526<p>
527Alternatively,
528if an error occurs,
529the callback is invoked as:
530</p>
531</font><pre>
532 uplevel #0 $callback [list "error" reason]
533</pre><font face="verdana, helvetica, arial, sans-serif" size="2">
534
535<p>
536Regardless,
537the return value of the final invocation of the callback is propagated
538upwards by mime::getbody.
539</p>
540
541<p>
542If the -command option is absent,
543then the return value of mime::getbody is a string containing the MIME
544part's entire body.
545</p>
546
547<h4><a name="mime_copymessage">3.7</a> mime::copymessage</h4>
548
549<p>
550mime::copymessage copies the MIME part to the specified channel.
551</p>
552
553<p>
554mime::copymessage operates synchronously,
555and uses fileevent to allow asynchronous operations to proceed
556independently.
557</p>
558
559<h4><a name="mime_buildmessage">3.7</a> mime::buildmessage</h4>
560
561<p>
562mime::buildmessage returns the MIME part as a string. It is similar
563to mime::copymessage, only it returns the data as a return string
564instead of writing to a channel.
565</p>
566
567
568<h4><a name="smtp_sendmessage">3.8</a> smtp::sendmessage</h4>
569
570<p>
571smtp::sendmessage sends a MIME part to an SMTP server.
572(Note that this procedure is in the "smtp" package,
573not the "mime" package.)
574</p>
575
576<p>
577The options are:
578
579<blockquote class="text"><dl>
580
581<dt> -servers:</dt>
582<dd>
583a list of SMTP servers
584(the default is "localhost");
585</dd>
586
587<dt> -ports:</dt>
588<dd>
589a list of SMTP ports
590(the default is 25);
591</dd>
592
593<dt> -queue:</dt>
594<dd>
595indicates that the SMTP server should be
596asked to queue the message for later processing;
597</dd>
598
599<dt> -atleastone:</dt>
600<dd>
601indicates that the SMTP server must find
602at least one recipient acceptable for the message to be sent;
603</dd>
604
605<dt> -originator:</dt>
606<dd>
607a string containing an 822-style address
608specification
609(if present the header isn't examined for an originator address);
610</dd>
611
612<dt> -recipients:</dt>
613<dd>
614a string containing one or more 822-style
615address specifications
616(if present the header isn't examined for recipient addresses); and,
617</dd>
618
619<dt> -header:</dt>
620<dd>
621a keyword/value pairing
622(may occur zero or more times).
623</dd>
624
625</dl></blockquote>
626
627</p>
628
629<p>
630If the -originator option is not present,
631the originator address is taken from "From" (or "Resent-From");
632similarly,
633if the -recipients option is not present,
634recipient addresses are taken from "To", "cc", and "Bcc" (or
635"Resent-To", and so on).
636Note that the header key/values supplied by the "-header" option
637(not those present in the MIME part)
638are consulted.
639Regardless,
640header key/values are added to the outgoing message as necessary to
641ensure that a valid 822-style message is sent.
642</p>
643
644<p>
645smtp::sendmessage returns a list indicating which recipients were
646unacceptable to the SMTP server.
647Each element of the list is another list,
648containing the address, an SMTP error code, and a textual diagnostic.
649Depending on the -atleastone option and the intended recipients,,
650a non-empty list may still indicate that the message was accepted by
651the server.
652</p>
653
654<h4><a name="mime_parseaddress">3.9</a> mime::parseaddress</h4>
655
656<p>
657mime::parseaddr takes a string containing one or more 822-style
658address specifications and returns a list of serialized arrays,
659one element for each address specified in the argument.
660</p>
661
662<p>
663Each serialized array contains these properties:
664</p>
665</font><pre>
666 property value
667 ======== =====
668 address local@domain
669 comment 822-style comment
670 domain the domain part (rhs)
671 error non-empty on a parse error
672 group this address begins a group
673 friendly user-friendly rendering
674 local the local part (lhs)
675 memberP this address belongs to a group
676 phrase the phrase part
677 proper 822-style address specification
678 route 822-style route specification (obsolete)
679</pre><font face="verdana, helvetica, arial, sans-serif" size="2">
680
681<p>
682Note that one or more of these properties may be empty.
683</p>
684
685<h4><a name="mime_parsedatetime">3.10</a> mime::parsedatetime</h4>
686
687<p>
688mime::parsedatetime takes a string containing an 822-style
689date-time specification and returns the specified property.
690</p>
691
692<p>
693The list of properties and their ranges are:
694</p>
695</font><pre>
696 property range
697 ======== =====
698 hour 0 .. 23
699 lmonth January, February, ..., December
700 lweekday Sunday, Monday, ... Saturday
701 mday 1 .. 31
702 min 0 .. 59
703 mon 1 .. 12
704 month Jan, Feb, ..., Dec
705 proper 822-style date-time specification
706 rclock elapsed seconds between then and now
707 sec 0 .. 59
708 wday 0 .. 6 (Sun .. Mon)
709 weekday Sun, Mon, ..., Sat
710 yday 1 .. 366
711 year 1900 ...
712 zone -720 .. 720 (minutes east of GMT)
713</pre><font face="verdana, helvetica, arial, sans-serif" size="2">
714
715<h4><a name="mime_mapencoding">3.10</a> mime::mapencoding</h4>
716
717<p>
718mime::mapencoding takes a string containing the name of a
719tcl encoding (see [encoding names]) and returns the MIME
720charset name for that encoding (or "" if the charset name
721is unknown).
722</p>
723
724<h4><a name="mime_reversemapencoding">3.10</a> mime::reversemapencoding</h4>
725
726<p>
727mime::reversemapencoding takes a string containing the name of a
728MIME charset tcl encoding (see [encoding names]) and returns the MIME
729charset name for that encoding (or "" if no known tcl encoding maps to
730the mime charset type).
731</p>
732
733<a name="anchor6"><br><hr size="1" shade="0"></a>
734<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b> TOC </b></font></a><br></td></tr></table>
735<h3>4. EXAMPLES</h3>
736</font><pre>
737package require mime 1.0
738package require smtp 1.0
739
740
741# create an image
742
743set imageT [mime::initialize -canonical image/gif \
744 -file logo.gif]
745
746
747# parse a message
748
749set messageT [mime::initialize -file example.msg]
750
751
752# recursively traverse a message looking for primary recipients
753
754proc traverse {token} {
755 set result ""
756
757# depth-first search
758 if {![catch { mime::getproperty $token parts } parts]} {
759 foreach part $parts {
760 set result [concat $result [traverse $part]]
761 }
762 }
763
764# one value for each line occuring in the header
765 foreach value [mime::getheader $token To] {
766 foreach addr [mime::parseaddress $value] {
767 catch { unset aprops }
768 array set aprops $addr
769 lappend result $aprops(address)
770 }
771 }
772
773 return $result
774}
775
776
777# create a multipart containing both, and a timestamp
778
779set multiT [mime::initialize -canonical multipart/mixed
780 -parts [list $imageT $messageT]]
781
782
783
784
785# send it to some friends
786
787smtp::sendmessage $multiT \
788 -header [list From "Marshall Rose <mrose@dbc.mtview.ca.us>"] \
789 -header [list To "Andreas Kupries <a.kupries@westend.com>"] \
790 -header [list cc "dnew@messagemedia.com (Darren New)"] \
791 -header [list Subject "test message..."]
792
793
794# clean everything up
795
796mime::finalize $multiT -subordinates all
797</pre><font face="verdana, helvetica, arial, sans-serif" size="2">
798<a name="rfc.references"><br><hr size="1" shade="0"></a>
799<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b> TOC </b></font></a><br></td></tr></table>
800<h3>
801References</h3>
802<table width="99%" border="0">
803<tr><td class="author-text" valign="top"><b><a name="RFC2045">[1]</a></b></td>
804<td class="author-text"><a href="mailto:ned@innosoft.com">Freed, N.</a> and <a href="mailto:nsb@messagemedia.com">N.S. Borenstein</a>, "<a href="http://info.internet.isi.edu/in-notes/rfc/files/rfc2045.txt">Multipurpose Internet Mail Extensions (MIME)
805Part One: Format of Internet Message Bodies</a>", RFC 2045, November 1996.</td></tr>
806<tr><td class="author-text" valign="top"><b><a name="RFC2046">[2]</a></b></td>
807<td class="author-text"><a href="mailto:ned@innosoft.com">Freed, N.</a> and <a href="mailto:nsb@messagemedia.com">N.S. Borenstein</a>, "<a href="http://info.internet.isi.edu/in-notes/rfc/files/rfc2046.txt">Multipurpose Internet Mail Extensions (MIME)
808Part Two: Media Types</a>", RFC 2046, November 1995.</td></tr>
809<tr><td class="author-text" valign="top"><b><a name="RFC822">[3]</a></b></td>
810<td class="author-text"><a href="mailto:DCrocker@UDel-Relay">Crocker, D.</a>, "<a href="http://info.internet.isi.edu/in-notes/rfc/files/rfc822.txt">Standard for the format of ARPA Internet Text Messages</a>", RFC 822, STD 11, August 1982.</td></tr>
811</table>
812
813<a name="rfc.authors"><br><hr size="1" shade="0"></a>
814<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b> TOC </b></font></a><br></td></tr></table>
815<h3>Author's Address</h3>
816<table width="99%" border="0" cellpadding="0" cellspacing="0">
817<tr><td class="author-text"> </td>
818<td class="author-text">Marshall T. Rose</td></tr>
819<tr><td class="author-text"> </td>
820<td class="author-text">Dover Beach Consulting, Inc.</td></tr>
821<tr><td class="author-text"> </td>
822<td class="author-text">POB 255268</td></tr>
823<tr><td class="author-text"> </td>
824<td class="author-text">Sacramento, CA 95865-5268</td></tr>
825<tr><td class="author-text"> </td>
826<td class="author-text">US</td></tr>
827<tr><td class="author" align="right">Phone: </td>
828<td class="author-text">+1 916 483 8878</td></tr>
829<tr><td class="author" align="right">Fax: </td>
830<td class="author-text">+1 916 483 8848</td></tr>
831<tr><td class="author" align="right">EMail: </td>
832<td class="author-text"><a href="mailto:mrose@dbc.mtview.ca.us">mrose@dbc.mtview.ca.us</a></td></tr>
833</table>
834
835<a name="anchor7"><br><hr size="1" shade="0"></a>
836<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b> TOC </b></font></a><br></td></tr></table>
837<h3>Appendix A. TODO List</h3>
838
839<p>
840
841<blockquote class="text"><dl>
842
843<dt>mime::initialize</dt>
844<dd>
845
846<ul class="text">
847
848<li>
849well-defined errorCode values
850</li>
851
852<li>
853catch nested errors when processing a multipart
854</li>
855
856</ul>
857
858</dd>
859
860</dl></blockquote>
861
862</p>
863
864<a name="anchor8"><br><hr size="1" shade="0"></a>
865<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b> TOC </b></font></a><br></td></tr></table>
866<h3>Appendix B. Acknowledgements</h3>
867
868<p>
869This package is influenced by the safe-tcl package
870(Borenstein and Rose, circa 1993),
871and also by <a href="mailto:dnew@messagemedia.com">Darren New</a>'s
872unpublished package of 1999.
873</p>
874
875<p>
876This package makes use of
877<a href="mailto:a.kupries@westend.com">Andreas Kupries</a>'s
878excellent Trf package.
879</p>
880</font></body></html>
881
1
2
3The README file M.T. Rose
4 Dover Beach Consulting, Inc.
5 February 22, 2000
6
7
8 Tcl MIME
9
10
11Abstract
12
13 Tcl MIME generates and parses MIME body parts.
14
15Table of Contents
16
17 1. SYNOPSIS . . . . . . . . . . . . . . . . . . . . . . . . . . 2
18 1.1 Requirements . . . . . . . . . . . . . . . . . . . . . . . . 3
19 1.2 Copyrights . . . . . . . . . . . . . . . . . . . . . . . . . 3
20 2. SYNTAX . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
21 3. SEMANTICS . . . . . . . . . . . . . . . . . . . . . . . . . 5
22 3.1 mime::initialize . . . . . . . . . . . . . . . . . . . . . . 5
23 3.2 mime::finalize . . . . . . . . . . . . . . . . . . . . . . . 5
24 3.3 mime::getproperty . . . . . . . . . . . . . . . . . . . . . 5
25 3.4 mime::getheader . . . . . . . . . . . . . . . . . . . . . . 6
26 3.5 mime::setheader . . . . . . . . . . . . . . . . . . . . . . 6
27 3.6 mime::getbody . . . . . . . . . . . . . . . . . . . . . . . 6
28 3.7 mime::copymessage . . . . . . . . . . . . . . . . . . . . . 7
29 3.8 mime::buildmessage . . . . . . . . . . . . . . . . . . . . . 7
30 3.9 smtp::sendmessage . . . . . . . . . . . . . . . . . . . . . 7
31 3.10 mime::parseaddress . . . . . . . . . . . . . . . . . . . . . 8
32 3.11 mime::parsedatetime . . . . . . . . . . . . . . . . . . . . 9
33 3.12 mime::mapencoding . . . . . . . . . . . . . . . . . . . . . 9
34 3.13 mime::reversemapencoding . . . . . . . . . . . . . . . . . . 9
35
36 4. EXAMPLES . . . . . . . . . . . . . . . . . . . . . . . . . . 10
37 References . . . . . . . . . . . . . . . . . . . . . . . . . 12
38 Author's Address . . . . . . . . . . . . . . . . . . . . . . 12
39 A. TODO List . . . . . . . . . . . . . . . . . . . . . . . . . 13
40 B. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . 14
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59Rose [Page 1]
60
61README Tcl MIME February 2000
62
63
641. SYNOPSIS
65
66 package provide mime 1.2
67 package provide smtp 1.2
68
69 Tcl MIME is an implementation of a Tcl package that generates and
70 parses MIME[1] body parts.
71
72 Each MIME part consists of a header (zero or more key/value pairs),
73 an empty line, and a structured body. A MIME part is either a "leaf"
74 or has (zero or more) subordinates.
75
76 MIME defines four keys that may appear in the headers:
77
78 Content-Type: describes the data contained in the body ("the
79 content");
80
81 Content-Transfer-Encoding: describes how the content is encoded
82 for transmission in an ASCII stream;
83
84 Content-Description: a textual description of the content; and,
85
86 Content-ID: a globally-unique identifier for the content.
87
88 Consult [2] for a list of standard content types. Further, consult
89 [3] for a list of several other header keys (e.g., "To", "cc", etc.)
90
91 A simple example might be:
92
93 Date: Sun, 04 July 1999 10:38:25 -0600
94 From: Marshall Rose <mrose@dbc.mtview.ca.us>
95 To: Andreas Kupries <a.kupries@westend.com>
96 cc: dnew@messagemedia.com (Darren New)
97 MIME-Version: 1.0
98 Content-Type: text/plain; charset="us-ascii"
99 Content-Description: a simple example
100 Content-ID: <4294407315.931384918.1@dbc.mtview.ca.us>
101
102 Here is the body. In this case, simply plain text.
103
104 In addition to an implementation of the mime package, Tcl MIME
105 includes an implementation of the smtp package.
106
107
108
109
110
111
112
113
114
115Rose [Page 2]
116
117README Tcl MIME February 2000
118
119
1201.1 Requirements
121
122 This package requires:
123
124 o Tcl/Tk version 8.0.3[4] or later
125
126 In addition, this package requires one of the following:
127
128 o Trf version 2.0p5[5] or later
129
130 o base64 version 2.0 or later (included with tcllib)
131
132 If it is available, Trf will be used to provide better performance;
133 if not, Tcl-only equivalent functions, based on the base64 package,
134 are used.
135
1361.2 Copyrights
137
138 (c) 1999-2000 Marshall T. Rose
139
140 Hold harmless the author, and any lawful use is allowed.
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179Rose [Page 3]
180
181README Tcl MIME February 2000
182
183
1842. SYNTAX
185
186 mime::initialize (Section 3.1) returns a token. Parameters:
187 ?-canonical type/subtype
188 ?-param {key value}?...
189 ?-encoding value?
190 ?-header {key value}?... ?
191 (-file name | -string value | -parts {token1 ... tokenN})
192
193 mime::finalize (Section 3.2) returns an empty string. Parameters:
194 token ?-subordinates "all" | "dynamic" | "none"?
195
196 mime::getproperty (Section 3.3) returns a string or a list of
197 strings. Parameters:
198 token ?property | -names?
199
200 mime::getheader (Section 3.4) returns a list of strings. Parameters:
201 token ?key | -names?
202
203 mime::setheader (Section 3.5) returns a list of strings. Parameters:
204 token key value ?-mode "write" | "append" | "delete"?
205
206 mime::getbody (Section 3.6) returns a string. Parameters:
207 ?-command callback ?-blocksize octets? ?
208
209 mime::copymessage (Section 3.7) returns an empty string. Parameters:
210 token channel
211
212 mime::buildmessage (Section 3.7) returns a string. Parameters:
213 token
214
215 smtp::sendmessage (Section 3.8) returns a list. Parameters:
216 token ?-servers list? ?-ports list?
217 ?-queue boolean? ?-atleastone boolean?
218 ?-originator string? ?-recipients string?
219 ?-header {key value}?...
220
221 mime::parseaddress (Section 3.9) returns a list of serialized
222 arrays. Parameters:
223 string
224
225 mime::parsedatetime (Section 3.10) returns a string. Parameters:
226 [string | -now] property
227
228 mime::mapencoding (Section 3.10) returns a string. Parameters:
229 encoding_name
230
231 mime::reversemapencoding (Section 3.10) returns a string. Parameters:
232 charset_type
233
234
235
236Rose [Page 4]
237
238README Tcl MIME February 2000
239
240
2413. SEMANTICS
242
2433.1 mime::initialize
244
245 mime::initialize creates a MIME part:
246
247 o If the -canonical option is present, then the body is in
248 canonical (raw) form and is found by consulting either the -file,
249 -string, or -part option.
250
251 In addition, both the -param and -header options may occur zero
252 or more times to specify "Content-Type" parameters (e.g.,
253 "charset") and header keyword/values (e.g.,
254 "Content-Disposition"), respectively.
255
256 Also, -encoding, if present, specifies the
257 "Content-Transfer-Encoding" when copying the body.
258
259 o If the -canonical option is not present, then the MIME part
260 contained in either the -file or the -string option is parsed,
261 dynamically generating subordinates as appropriate.
262
2633.2 mime::finalize
264
265 mime::finalize destroys a MIME part.
266
267 If the -subordinates option is present, it specifies which
268 subordinates should also be destroyed. The default value is
269 "dynamic".
270
2713.3 mime::getproperty
272
273 mime::getproperty returns the properties of a MIME part.
274
275 The properties are:
276
277 property value
278 ======== =====
279 content the type/subtype describing the content
280 encoding the "Content-Transfer-Encoding"
281 params a list of "Content-Type" parameters
282 parts a list of tokens for the part's subordinates
283 size the approximate size of the content (unencoded)
284
285 The "parts" property is present only if the MIME part has
286 subordinates.
287
288 If mime::getproperty is invoked with the name of a specific
289 property, then the corresponding value is returned; instead, if
290
291
292Rose [Page 5]
293
294README Tcl MIME February 2000
295
296
297 -names is specified, a list of all properties is returned;
298 otherwise, a serialized array of properties and values is returned.
299
3003.4 mime::getheader
301
302 mime::getheader returns the header of a MIME part.
303
304 A header consists of zero or more key/value pairs. Each value is a
305 list containing one or more strings.
306
307 If mime::getheader is invoked with the name of a specific key, then
308 a list containing the corresponding value(s) is returned; instead,
309 if -names is specified, a list of all keys is returned; otherwise, a
310 serialized array of keys and values is returned. Note that when a
311 key is specified (e.g., "Subject"), the list returned usually
312 contains exactly one string; however, some keys (e.g., "Received")
313 often occur more than once in the header, accordingly the list
314 returned usually contains more than one string.
315
3163.5 mime::setheader
317
318 mime::setheader writes, appends to, or deletes the value associated
319 with a key in the header.
320
321 The value for -mode is one of:
322
323 write: the key/value is either created or overwritten (the
324 default);
325
326 append: a new value is appended for the key (creating it as
327 necessary); or,
328
329 delete: all values associated with the key are removed (the
330 "value" parameter is ignored).
331
332 Regardless, mime::setheader returns the previous value associated
333 with the key.
334
3353.6 mime::getbody
336
337 mime::getbody returns the body of a leaf MIME part in canonical form.
338
339 If the -command option is present, then it is repeatedly invoked
340 with a fragment of the body as this:
341
342 uplevel #0 $callback [list "data" $fragment]
343
344 (The -blocksize option, if present, specifies the maximum size of
345 each fragment passed to the callback.)
346
347
348Rose [Page 6]
349
350README Tcl MIME February 2000
351
352
353 When the end of the body is reached, the callback is invoked as:
354
355 uplevel #0 $callback "end"
356
357 Alternatively, if an error occurs, the callback is invoked as:
358
359 uplevel #0 $callback [list "error" reason]
360
361 Regardless, the return value of the final invocation of the callback
362 is propagated upwards by mime::getbody.
363
364 If the -command option is absent, then the return value of
365 mime::getbody is a string containing the MIME part's entire body.
366
3673.7 mime::copymessage
368
369 mime::copymessage copies the MIME part to the specified channel.
370
371 mime::copymessage operates synchronously, and uses fileevent to
372 allow asynchronous operations to proceed independently.
373
3743.7 mime::buildmessage
375
376 mime::buildmessage returns the MIME part as a string. It is similar
377 to mime::copymessage, only it returns the data as a return string
378 instead of writing to a channel.
379
3803.8 smtp::sendmessage
381
382 smtp::sendmessage sends a MIME part to an SMTP server. (Note that
383 this procedure is in the "smtp" package, not the "mime" package.)
384
385 The options are:
386
387 -servers: a list of SMTP servers (the default is "localhost");
388
389 -ports: a list of SMTP ports (the default is 25)
390
391 -queue: indicates that the SMTP server should be asked to queue
392 the message for later processing;
393
394 -atleastone: indicates that the SMTP server must find at least
395 one recipient acceptable for the message to be sent;
396
397 -originator: a string containing an 822-style address
398 specification (if present the header isn't examined for an
399 originator address);
400
401 -recipients: a string containing one or more 822-style address
402 specifications (if present the header isn't examined for
403 recipient addresses); and,
404
405 -header: a keyword/value pairing (may occur zero or more times).
406
407 If the -originator option is not present, the originator address is
408 taken from "From" (or "Resent-From"); similarly, if the -recipients
409 option is not present, recipient addresses are taken from "To",
410
411
412Rose [Page 7]
413
414README Tcl MIME February 2000
415
416
417 "cc", and "Bcc" (or "Resent-To", and so on). Note that the header
418 key/values supplied by the "-header" option (not those present in
419 the MIME part) are consulted. Regardless, header key/values are
420 added to the outgoing message as necessary to ensure that a valid
421 822-style message is sent.
422
423 smtp::sendmessage returns a list indicating which recipients were
424 unacceptable to the SMTP server. Each element of the list is another
425 list, containing the address, an SMTP error code, and a textual
426 diagnostic. Depending on the -atleastone option and the intended
427 recipients,, a non-empty list may still indicate that the message
428 was accepted by the server.
429
4303.9 mime::parseaddress
431
432 mime::parseaddr takes a string containing one or more 822-style
433 address specifications and returns a list of serialized arrays, one
434 element for each address specified in the argument.
435
436 Each serialized array contains these properties:
437
438 property value
439 ======== =====
440 address local@domain
441 comment 822-style comment
442 domain the domain part (rhs)
443 error non-empty on a parse error
444 group this address begins a group
445 friendly user-friendly rendering
446 local the local part (lhs)
447 memberP this address belongs to a group
448 phrase the phrase part
449 proper 822-style address specification
450 route 822-style route specification (obsolete)
451
452 Note that one or more of these properties may be empty.
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467Rose [Page 8]
468
469README Tcl MIME February 2000
470
471
4723.10 mime::parsedatetime
473
474 mime::parsedatetime takes a string containing an 822-style date-time
475 specification and returns the specified property.
476
477 The list of properties and their ranges are:
478
479 property range
480 ======== =====
481 hour 0 .. 23
482 lmonth January, February, ..., December
483 lweekday Sunday, Monday, ... Saturday
484 mday 1 .. 31
485 min 0 .. 59
486 mon 1 .. 12
487 month Jan, Feb, ..., Dec
488 proper 822-style date-time specification
489 rclock elapsed seconds between then and now
490 sec 0 .. 59
491 wday 0 .. 6 (Sun .. Mon)
492 weekday Sun, Mon, ..., Sat
493 yday 1 .. 366
494 year 1900 ...
495 zone -720 .. 720 (minutes east of GMT)
496
4973.10 mime::mapencoding
498
499 mime::mapencodings maps tcl encodings onto the proper names for their
500 MIME charset type. This is only done for encodings whose charset types
501 were known. The remaining encodings return "" for now.
502
5033.10 mime::reversemapencoding
504
505 mime::reversemapencoding maps MIME charset types onto tcl encoding names.
506 Those that are unknown return "".
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523Rose [Page 9]
524
525README Tcl MIME February 2000
526
527
5284. EXAMPLES
529
530 package require mime 1.0
531 package require smtp 1.0
532
533
534 # create an image
535
536 set imageT [mime::initialize -canonical image/gif \
537 -file logo.gif]
538
539
540 # parse a message
541
542 set messageT [mime::initialize -file example.msg]
543
544
545 # recursively traverse a message looking for primary recipients
546
547 proc traverse {token} {
548 set result ""
549
550 # depth-first search
551 if {![catch { mime::getproperty $token parts } parts]} {
552 foreach part $parts {
553 set result [concat $result [traverse $part]]
554 }
555 }
556
557 # one value for each line occuring in the header
558 foreach value [mime::getheader $token To] {
559 foreach addr [mime::parseaddress $value] {
560 catch { unset aprops }
561 array set aprops $addr
562 lappend result $aprops(address)
563 }
564 }
565
566 return $result
567 }
568
569
570 # create a multipart containing both, and a timestamp
571
572 set multiT [mime::initialize -canonical multipart/mixed
573 -parts [list $imageT $messageT]]
574
575
576
577
578
579Rose [Page 10]
580
581README Tcl MIME February 2000
582
583
584 # send it to some friends
585
586 smtp::sendmessage $multiT \
587 -header [list From "Marshall Rose <mrose@dbc.mtview.ca.us>"] \
588 -header [list To "Andreas Kupries <a.kupries@westend.com>"] \
589 -header [list cc "dnew@messagemedia.com (Darren New)"] \
590 -header [list Subject "test message..."]
591
592
593 # clean everything up
594
595 mime::finalize $multiT -subordinates all
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635Rose [Page 11]
636
637README Tcl MIME February 2000
638
639
640References
641
642 [1] Freed, N. and N.S. Borenstein, "Multipurpose Internet Mail
643 Extensions (MIME) Part One: Format of Internet Message Bodies",
644 RFC 2045, November 1996.
645
646 [2] Freed, N. and N.S. Borenstein, "Multipurpose Internet Mail
647 Extensions (MIME) Part Two: Media Types", RFC 2046, November
648 1995.
649
650 [3] Crocker, D., "Standard for the format of ARPA Internet Text
651 Messages", RFC 822, STD 11, August 1982.
652
653 [4] http://www.scriptics.com/software/8.1.html
654
655 [5] http://www.oche.de/~akupries/soft/trf/
656
657 [6] mailto:dnew@messagemedia.com
658
659 [7] mailto:a.kupries@westend.com
660
661
662Author's Address
663
664 Marshall T. Rose
665 Dover Beach Consulting, Inc.
666 POB 255268
667 Sacramento, CA 95865-5268
668 US
669
670 Phone: +1 916 483 8878
671 Fax: +1 916 483 8848
672 EMail: mrose@dbc.mtview.ca.us
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691Rose [Page 12]
692
693README Tcl MIME February 2000
694
695
696Appendix A. TODO List
697
698 mime::initialize
699
700 * well-defined errorCode values
701
702 * catch nested errors when processing a multipart
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747Rose [Page 13]
748
749README Tcl MIME February 2000
750
751
752Appendix B. Acknowledgements
753
754 This package is influenced by the safe-tcl package (Borenstein and
755 Rose, circa 1993), and also by Darren New[6]'s unpublished package
756 of 1999.
757
758 This package makes use of Andreas Kupries[7]'s excellent Trf package.
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803Rose [Page 14]
804
805
1<?xml version="1.0"?>
2<!DOCTYPE rfc SYSTEM "rfc2629.dtd">
3
4<?rfc compact="no"?>
5<?rfc toc="yes"?>
6<?rfc private="The README file"?>
7<?rfc header="README"?>
8
9<rfc>
10<front>
11<title>Tcl MIME</title>
12
13<author initials="M.T." surname="Rose" fullname="Marshall T. Rose">
14<organization>Dover Beach Consulting, Inc.</organization>
15<address>
16<postal>
17<street>POB 255268</street>
18<city>Sacramento</city> <region>CA</region> <code>95865-5268</code>
19<country>US</country>
20</postal>
21<phone>+1 916 483 8878</phone>
22<facsimile>+1 916 483 8848</facsimile>
23<email>mrose@dbc.mtview.ca.us</email>
24</address>
25</author>
26
27<date month="February" year="2000" />
28
29<abstract><t>Tcl MIME generates and parses MIME body parts.</t></abstract>
30</front>
31
32<middle>
33
34<section title="SYNOPSIS">
35<figure><artwork><![CDATA[
36 package provide mime 1.2
37 package provide smtp 1.2
38]]></artwork></figure>
39
40<t>Tcl MIME is an implementation of a Tcl package that generates and
41parses <xref target="RFC2045">MIME</xref> body parts.</t>
42
43<t>Each MIME part consists of a header
44(zero or more key/value pairs),
45an empty line,
46and a structured body.
47A MIME part is either a "leaf" or has (zero or more) subordinates.</t>
48
49<t>MIME defines four keys that may appear in the headers:
50<list style="hanging">
51<t hangText=" Content-Type:">describes the data contained in the body
52("the content");</t>
53
54<t hangText=" Content-Transfer-Encoding:">describes how the content is
55encoded for transmission in an ASCII stream;</t>
56
57<t hangText=" Content-Description:">a textual description of the
58content; and,</t>
59
60<t hangText=" Content-ID:">a globally-unique identifier for the
61content.</t>
62</list></t>
63
64<t>Consult <xref target="RFC2046" /> for a list of standard content types.
65Further,
66consult <xref target="RFC822" /> for a list of several other header keys
67(e.g., "To", "cc", etc.)</t>
68
69<figure>
70<preamble>A simple example might be:</preamble>
71<artwork><![CDATA[
72 Date: Sun, 04 July 1999 10:38:25 -0600
73 From: Marshall Rose <mrose@dbc.mtview.ca.us>
74 To: Andreas Kupries <a.kupries@westend.com>
75 cc: dnew@messagemedia.com (Darren New)
76 MIME-Version: 1.0
77 Content-Type: text/plain; charset="us-ascii"
78 Content-Description: a simple example
79 Content-ID: <4294407315.931384918.1@dbc.mtview.ca.us>
80
81 Here is the body. In this case, simply plain text.
82]]></artwork>
83</figure>
84
85<t>In addition to an implementation of the mime package,
86Tcl MIME includes an implementation of the smtp package.</t>
87
88<vspace blankLines="1000" />
89
90<section title="Requirements">
91<t>This package requires:
92<list style="symbols">
93<t><eref target="http://www.scriptics.com/software/8.1.html">Tcl/Tk version 8.0.3</eref>
94</list>
95or later</t>
96<t>In addition, this package requires one of the following:</t>
97<list style="symbols">
98<t><eref target="http://www.oche.de/~akupries/soft/trf/">Trf version 2.0p5</eref>
99or later</t>
100<t><eref target="http://dev.ajubasolutions.com/software/tcllib/">base 64 version 2.0</eref> or later (included with tcllib)</t>
101</list></t>
102<t>If it is available, Trf will be used to provide better performance;
103if not, Tcl-only equivalent functions, based on the base64 package,
104are used.</t>
105</section>
106
107<section title="Copyrights">
108<t>(c) 1999-2000 Marshall T. Rose</t>
109
110<t>Hold harmless the author, and any lawful use is allowed.</t>
111</section>
112</section>
113
114<section title="SYNTAX">
115<figure>
116<preamble><xref target="mime_initialize">mime::initialize</xref>
117returns a token.
118Parameters:</preamble>
119<artwork><![CDATA[ ?-canonical type/subtype
120 ?-param {key value}?...
121 ?-encoding value?
122 ?-header {key value}?... ?
123 (-file name | -string value | -parts {token1 ... tokenN})
124]]></artwork>
125</figure>
126
127<figure>
128<preamble><xref target="mime_finalize">mime::finalize</xref> returns
129an empty string.
130Parameters:</preamble>
131<artwork><![CDATA[ token ?-subordinates "all" | "dynamic" | "none"?
132]]></artwork>
133</figure>
134
135<figure>
136<preamble><xref target="mime_getproperty">mime::getproperty</xref>
137returns a string or a list of strings.
138Parameters:</preamble>
139<artwork><![CDATA[ token ?property | -names?
140]]></artwork>
141</figure>
142
143<figure>
144<preamble><xref target="mime_getheader">mime::getheader</xref> returns
145a list of strings.
146Parameters:</preamble>
147<artwork><![CDATA[ token ?key | -names?
148]]></artwork>
149</figure>
150
151<figure>
152<preamble><xref target="mime_setheader">mime::setheader</xref> returns
153a list of strings.
154Parameters:</preamble>
155<artwork><![CDATA[ token key value ?-mode "write" | "append" | "delete"?
156]]></artwork>
157</figure>
158
159<figure>
160<preamble><xref target="mime_getbody">mime::getbody</xref> returns a string.
161Parameters:</preamble>
162<artwork><![CDATA[ ?-command callback ?-blocksize octets? ?
163]]></artwork>
164</figure>
165
166<figure>
167<preamble><xref target="mime_copymessage">mime::copymessage</xref>
168returns an empty string.
169Parameters:</preamble>
170<artwork><![CDATA[ token channel
171]]></artwork>
172</figure>
173
174<figure>
175<preamble><xref target="mime_buildmessage">mime::buildmessage</xref>
176returns an empty string.
177Parameters:</preamble>
178<artwork><![CDATA[ token
179]]></artwork>
180</figure>
181
182<figure>
183<preamble><xref target="smtp_sendmessage">smtp::sendmessage</xref>
184returns a list.
185Parameters:</preamble>
186<artwork><![CDATA[ token ?-servers list? ?-ports list?
187 ?-queue boolean? ?-atleastone boolean?
188 ?-originator string? ?-recipients string?
189 ?-header {key value}?...
190]]></artwork>
191</figure>
192
193<figure>
194<preamble><xref target="mime_parseaddress">mime::parseaddress</xref>
195returns a list of serialized arrays.
196Parameters:</preamble>
197<artwork><![CDATA[ string
198]]></artwork>
199</figure>
200
201<figure>
202<preamble><xref target="mime_parsedatetime">mime::parsedatetime</xref>
203returns a string.
204Parameters:</preamble>
205<artwork><![CDATA[ [string | -now] property
206]]></artwork>
207</figure>
208
209<figure>
210<preamble><xref target="mime_mapencoding">mime::mapencoding</xref>
211returns a string.
212Parameters:</preamble>
213<artwork><![CDATA[ encoding_name
214]]></artwork>
215</figure>
216
217<figure>
218<preamble><xref target="mime_reversemapencoding">mime::reversemapencoding</xref>
219returns a string.
220Parameters:</preamble>
221<artwork><![CDATA[ content_type
222]]></artwork>
223</figure>
224
225</section>
226
227<section title="SEMANTICS">
228
229<section anchor="mime_initialize" title="mime::initialize">
230<t>mime::initialize creates a MIME part:
231<list style="symbols">
232<t>If the -canonical option is present,
233then the body is in canonical (raw) form and is found by consulting
234either the -file, -string, or -part option.
235<vspace blankLines="1" />
236In addition,
237both the -param and -header options may occur zero or more times to
238specify "Content-Type" parameters (e.g., "charset")
239and header keyword/values (e.g., "Content-Disposition"),
240respectively.
241<vspace blankLines="1" />
242Also, -encoding, if present,
243specifies the "Content-Transfer-Encoding" when copying the body.</t>
244
245<t>If the -canonical option is not present,
246then the MIME part contained in either the -file or the -string option
247is parsed,
248dynamically generating subordinates as appropriate.</t>
249</list></t>
250</section>
251
252<section anchor="mime_finalize" title="mime::finalize">
253<t>mime::finalize destroys a MIME part.</t>
254
255<t>If the -subordinates option is present,
256it specifies which subordinates should also be destroyed.
257The default value is "dynamic".</t>
258</section>
259
260<section anchor="mime_getproperty" title="mime::getproperty">
261<t>mime::getproperty returns the properties of a MIME part.</t>
262
263<figure>
264<preamble>The properties are:</preamble>
265<artwork><![CDATA[
266 property value
267 ======== =====
268 content the type/subtype describing the content
269 encoding the "Content-Transfer-Encoding"
270 params a list of "Content-Type" parameters
271 parts a list of tokens for the part's subordinates
272 size the approximate size of the content (unencoded)
273]]></artwork>
274<postamble>The "parts" property is present only if the MIME part has
275subordinates.</postamble>
276</figure>
277
278<t>If mime::getproperty is invoked with the name of a specific property,
279then the corresponding value is returned;
280instead,
281if -names is specified,
282a list of all properties is returned;
283otherwise,
284a serialized array of properties and values is returned.</t>
285</section>
286
287<section anchor="mime_getheader" title="mime::getheader">
288<t>mime::getheader returns the header of a MIME part.</t>
289
290<t>A header consists of zero or more key/value pairs.
291Each value is a list containing one or more strings.</t>
292
293<t>If mime::getheader is invoked with the name of a specific key,
294then a list containing the corresponding value(s) is returned;
295instead,
296if -names is specified,
297a list of all keys is returned;
298otherwise,
299a serialized array of keys and values is returned.
300Note that when a key is specified (e.g., "Subject"),
301the list returned usually contains exactly one string;
302however,
303some keys (e.g., "Received") often occur more than once in the header,
304accordingly the list returned usually contains more than one string.</t>
305</section>
306
307<section anchor="mime_setheader" title="mime::setheader">
308<t>mime::setheader writes, appends to, or deletes the value associated
309with a key in the header.</t>
310
311<t>The value for -mode is one of:
312<list style="hanging">
313<t hangText=" write:"> the key/value is either created or
314overwritten (the default);</t>
315
316<t hangText=" append:"> a new value is appended for the key
317(creating it as necessary); or,</t>
318
319<t hangText=" delete:"> all values associated with the key are removed
320(the "value" parameter is ignored).</t>
321</list></t>
322
323<t>Regardless,
324mime::setheader returns the previous value associated with the key.</t>
325</section>
326
327<section anchor="mime_getbody" title="mime::getbody">
328<t>mime::getbody returns the body of a leaf MIME part in canonical form.</t>
329
330<figure>
331<preamble>If the -command option is present,
332then it is repeatedly invoked with a fragment of the body as this:</preamble>
333<artwork><![CDATA[
334 uplevel #0 $callback [list "data" $fragment]
335]]></artwork>
336<postamble>(The -blocksize option,
337if present,
338specifies the maximum size of each fragment passed to the
339callback.)</postamble>
340</figure>
341
342<figure>
343<preamble>When the end of the body is reached,
344the callback is invoked as:</preamble>
345<artwork><![CDATA[
346 uplevel #0 $callback "end"
347]]></artwork>
348</figure>
349
350<figure>
351<preamble>Alternatively,
352if an error occurs,
353the callback is invoked as:</preamble>
354<artwork><![CDATA[
355 uplevel #0 $callback [list "error" reason]
356]]></artwork>
357</figure>
358
359<t>Regardless,
360the return value of the final invocation of the callback is propagated
361upwards by mime::getbody.</t>
362
363<t>If the -command option is absent,
364then the return value of mime::getbody is a string containing the MIME
365part's entire body.</t>
366</section>
367
368<section anchor="mime_copymessage" title="mime::copymessage">
369<t>mime::copymessage copies the MIME part to the specified channel.</t>
370
371<t>mime::copymessage operates synchronously,
372and uses fileevent to allow asynchronous operations to proceed
373independently.</t>
374</section>
375
376<section anchor="mime_buildmessage" title="mime::buildmessage">
377<t>mime::buildmessage returns the MIME part as a string. It is similar
378to mime::copymessage, only it returns the data as a return string
379instead of writing to a channel.</t>
380</section>
381
382<section anchor="smtp_sendmessage" title="smtp::sendmessage">
383<t>smtp::sendmessage sends a MIME part to an SMTP server.
384(Note that this procedure is in the "smtp" package,
385not the "mime" package.)</t>
386
387<t>The options are:
388<list style="hanging">
389<t hangText=" -servers:">a list of SMTP servers
390(the default is "localhost");</t>
391
392<t hangText=" -ports:">a list of SMTP ports
393(the default is 25);</t>
394
395<t hangText=" -queue:">indicates that the SMTP server should be
396asked to queue the message for later processing;</t>
397
398<t hangText=" -atleastone:">indicates that the SMTP server must find
399at least one recipient acceptable for the message to be sent;</t>
400
401<t hangText=" -originator:">a string containing an 822-style address
402specification
403(if present the header isn't examined for an originator address);</t>
404
405<t hangText=" -recipients:">a string containing one or more 822-style
406address specifications
407(if present the header isn't examined for recipient addresses); and,</t>
408
409<t hangText=" -header:">a keyword/value pairing
410(may occur zero or more times).</t>
411</list></t>
412
413<t>If the -originator option is not present,
414the originator address is taken from "From" (or "Resent-From");
415similarly,
416if the -recipients option is not present,
417recipient addresses are taken from "To", "cc", and "Bcc" (or
418"Resent-To", and so on).
419Note that the header key/values supplied by the "-header" option
420(not those present in the MIME part)
421are consulted.
422Regardless,
423header key/values are added to the outgoing message as necessary to
424ensure that a valid 822-style message is sent.</t>
425
426<t>smtp::sendmessage returns a list indicating which recipients were
427unacceptable to the SMTP server.
428Each element of the list is another list,
429containing the address, an SMTP error code, and a textual diagnostic.
430Depending on the -atleastone option and the intended recipients,,
431a non-empty list may still indicate that the message was accepted by
432the server.</t>
433</section>
434
435<section anchor="mime_parseaddress" title="mime::parseaddress">
436<t>mime::parseaddr takes a string containing one or more 822-style
437address specifications and returns a list of serialized arrays,
438one element for each address specified in the argument.</t>
439
440<figure>
441<preamble>Each serialized array contains these properties:</preamble>
442<artwork><![CDATA[
443 property value
444 ======== =====
445 address local@domain
446 comment 822-style comment
447 domain the domain part (rhs)
448 error non-empty on a parse error
449 group this address begins a group
450 friendly user-friendly rendering
451 local the local part (lhs)
452 memberP this address belongs to a group
453 phrase the phrase part
454 proper 822-style address specification
455 route 822-style route specification (obsolete)
456]]></artwork>
457<postamble>Note that one or more of these properties may be empty.</postamble>
458</figure>
459</section>
460
461<vspace blankLines="10000" />
462
463<section anchor="mime_parsedatetime" title="mime::parsedatetime">
464<t>mime::parsedatetime takes a string containing an 822-style
465date-time specification and returns the specified property.</t>
466
467<figure>
468<preamble>The list of properties and their ranges are:</preamble>
469<artwork><![CDATA[
470 property range
471 ======== =====
472 hour 0 .. 23
473 lmonth January, February, ..., December
474 lweekday Sunday, Monday, ... Saturday
475 mday 1 .. 31
476 min 0 .. 59
477 mon 1 .. 12
478 month Jan, Feb, ..., Dec
479 proper 822-style date-time specification
480 rclock elapsed seconds between then and now
481 sec 0 .. 59
482 wday 0 .. 6 (Sun .. Mon)
483 weekday Sun, Mon, ..., Sat
484 yday 1 .. 366
485 year 1900 ...
486 zone -720 .. 720 (minutes east of GMT)
487]]></artwork>
488</figure>
489</section>
490
491<section anchor="mime_mapencoding" title="mime::mapencoding">
492<t>mime::mapencoding maps tcl encodings onto the proper names for their
493MIME charset type. This is only done for encodings whose charset types
494were known. The remaining encodings return "" for now.</t>
495</section>
496
497<section anchor="mime_reversemapencoding" title="mime::reversemapencoding">
498<t>mime::reversemapencoding maps MIME charset types onto tcl encoding names.
499Those that are unknown return "".</t>
500</section>
501
502</section>
503
504<section title="EXAMPLES">
505<figure>
506<artwork><![CDATA[
507package require mime 1.0
508package require smtp 1.0
509
510
511# create an image
512
513set imageT [mime::initialize -canonical image/gif \
514 -file logo.gif]
515
516
517# parse a message
518
519set messageT [mime::initialize -file example.msg]
520
521
522# recursively traverse a message looking for primary recipients
523
524proc traverse {token} {
525 set result ""
526
527# depth-first search
528 if {![catch { mime::getproperty $token parts } parts]} {
529 foreach part $parts {
530 set result [concat $result [traverse $part]]
531 }
532 }
533
534# one value for each line occuring in the header
535 foreach value [mime::getheader $token To] {
536 foreach addr [mime::parseaddress $value] {
537 catch { unset aprops }
538 array set aprops $addr
539 lappend result $aprops(address)
540 }
541 }
542
543 return $result
544}
545
546
547# create a multipart containing both, and a timestamp
548
549set multiT [mime::initialize -canonical multipart/mixed
550 -parts [list $imageT $messageT]]
551
552
553
554
555# send it to some friends
556
557smtp::sendmessage $multiT \
558 -header [list From "Marshall Rose <mrose@dbc.mtview.ca.us>"] \
559 -header [list To "Andreas Kupries <a.kupries@westend.com>"] \
560 -header [list cc "dnew@messagemedia.com (Darren New)"] \
561 -header [list Subject "test message..."]
562
563
564# clean everything up
565
566mime::finalize $multiT -subordinates all
567]]></artwork>
568</figure>
569</section>
570
571</middle>
572
573<back>
574<references>
575<reference anchor="RFC2045">
576<front>
577<title>Multipurpose Internet Mail Extensions (MIME)
578Part One: Format of Internet Message Bodies</title>
579<author initials="N." surname="Freed" fullname="Ned Freed">
580<organization>Innosoft International, Inc.</organization>
581<address>
582<email>ned@innosoft.com</email>
583</address>
584</author>
585<author initials="N.S." surname="Borenstein"
586 fullname="Nathaniel S. Borenstein">
587<organization>First Virtual Holdings, Incorporated</organization>
588<address>
589<email>nsb@messagemedia.com</email>
590</address>
591</author>
592<date month="November" year="1996"/>
593</front>
594<seriesInfo name="RFC" value="2045" />
595</reference>
596
597<reference anchor="RFC2046">
598<front>
599<title>Multipurpose Internet Mail Extensions (MIME)
600Part Two: Media Types</title>
601<author initials="N." surname="Freed" fullname="Ned Freed">
602<organization>Innosoft International, Inc.</organization>
603<address>
604<email>ned@innosoft.com</email>
605</address>
606</author>
607<author initials="N.S." surname="Borenstein"
608 fullname="Nathaniel S. Borenstein">
609<organization>First Virtual Holdings, Incorporated</organization>
610<address>
611<email>nsb@messagemedia.com</email>
612</address>
613</author>
614<date month="November" year="1995"/>
615</front>
616<seriesInfo name="RFC" value="2046" />
617</reference>
618
619<reference anchor="RFC822">
620<front>
621<title>Standard for the format of ARPA Internet Text Messages</title>
622<author initials="D." surname="Crocker" fullname="Dave Crocker">
623<organization abbrev="UDEL">University of Delaware</organization>
624<address>
625<email>DCrocker@UDel-Relay</email>
626</address>
627</author>
628<date month="August" year="1982"/>
629</front>
630<seriesInfo name="RFC" value="822" />
631<seriesInfo name="STD" value="11" />
632</reference>
633
634</references>
635
636<section title="TODO List">
637<t><list style="hanging">
638<t hangText="mime::initialize">
639<list style="symbols">
640<t>well-defined errorCode values</t>
641
642<t>catch nested errors when processing a multipart</t>
643</list></t>
644
645</list></t>
646</section>
647
648<section title="Acknowledgements">
649<t>This package is influenced by the safe-tcl package
650(Borenstein and Rose, circa 1993),
651and also by <eref target="mailto:dnew@messagemedia.com">Darren New</eref>'s
652unpublished package of 1999.</t>
653
654<t>This package makes use of
655<eref target="mailto:a.kupries@westend.com">Andreas Kupries</eref>'s
656excellent Trf package.</t>
657</section>
658
659</back>
660</rfc>
661