Generating mail messages is a very complicated procedure.
Netsendmail provides a comparatively simple interface
to accomplish this task without knowing too much about the details
of the mail format. Here is a kind of cookbook:
In the simplest case, the mail is an ASCII text. Generate the mail with
compose ~from_addr ~to_addrs ~subject main_text
Here, from_addr is the sender's address as pair (name,formal_address),
and to_addrs is the list of recipients in the same format.
The variable subject contains the subject of the message as string.
Finally, main_text is the ASCII text.
When addresses or the main text contain non-ASCII characters, you
should care about the in_charset and out_charset parameters.
In general, the strings you pass to compose are encoded as
in_charset, and the strings in the generated mail are encoded
as out_charset. Usually, it is a good idea to have
in_charset = out_charset, or out_charset as a superset of
in_charset (otherwise you might get conversion errors).
The default for both parameters is `Enc_iso88591.
Not everything can be internationalised. In particular, the subject,
the informal names of mail addresses, the content_description, and
the main text can be encoded in a non-ASCII character set. Especially,
the formal mail addresses cannot be internationalised. Example:
compose
~in_charset:`Enc_iso885915
~out_charset:`Enc_iso885915
~from_addr:("Heinz Dräger", "heinz\@draeger.de")
~to_addr:("Marion Schröder", "marion\@irgendwo.de")
~subject:"Geschäftlich"
"Verkaufe Teddy-Bären für 100¤"
Note that when you also pass content_type, the main text is
no longer converted according to in_charset and out_charset.
It is expected that the main text has already the right encoding,
and that the encoding is indicated by the content_type. Example:
compose
~in_charset:`Enc_iso885915
~out_charset:`Enc_iso885915
~from_addr:("Heinz Dräger", "heinz\@draeger.de")
~to_addr:("Marion Schröder", "marion\@irgendwo.de")
~content_type:("text/html", ["charset", Mimestring.mk_param "ISO-8859-1"])
~subject:"Geschäftlich"
"<html><body>Verkaufe Teddy-Bären für 100€</body></html>"
Here, the header fields are encoded in ISO-8859-15, but the main
text uses ISO-8859-1.
The function Mimestring.mk_param encapsulates parameter values for
several kinds of structured values that may occur in mail headers,
here for Content-type. This function takes care of the appropriate
representation of the parameter value (e.g. for parameters like "title"
that can be internationalised).
An attachment can simply be passed to compose. For example, to
add a file "foo.gif":
compose
...
attachments:[ wrap_attachment
~content_type:("image/gif", [])
(new Netmime.file_mime_body "foo.gif") ]
...
This creates a multipart/mixed mail. The class
Netmime.file_mime_body encapsulates a file as a MIME body that
can be attached to the mail (note: The file is not read as a whole
into memory, but only chunk by chunk, so you can even attach large
files without exhausting memory).
The type multipart/mixed has the special feature that
the attached parts can
either by displayed "inline" with the other contents, or suggested
for saving in a file. This hint is indicated by the Content-disposition
header. For example, to have the first attachment "inline", and the
second as a file with name "foo.gif", use:
compose
...
attachments:[ wrap_attachment
~content_type:("image/gif", [])
~content_disposition:("inline", [])
(new Netmime.file_mime_body "foo.gif");
wrap_attachment
~content_type:("image/gif", [])
~content_disposition:("attachment", ["filename",
Mimestring.mk_param "foo.gif"])
(new Netmime.file_mime_body "foo.gif") ]
...
It is possible to generate messages where the main part is
available in several formats, e.g. in text/plain and
text/html. The mail reader program can select which format
can be presented best to the user.
The compose function is not the right means to produce such
a mail. It is better to use the more capable functions
wrap_parts and wrap_mail for this purpose.
For example, to get a message with the text/plain version
s_plain and the text/html version s_html, use:
wrap_mail
~from_addr ~to_addrs ~subject
(wrap_parts
~content_type:("multipart/alternative", [])
[ wrap_attachment
~content_type:("text/plain", [])
(new Netmime.memory_mime_body s_plain);
wrap_attachment
~content_type:("text/html", [])
(new Netmime.memory_mime_body s_html)
])
Here, wrap_attachment is used to encapsulate the two versions of
the main text. This works because there is no difference between the
format of an attachment and the format of a text part. (Actually,
wrap_attachment should be better called wrap_body.) The class
Netmime.memory_mime_body encapsulates a string as MIME body.
The function wrap_parts bundles the two versions to the main
message, and wrap_mail adds the mail headers necessary to deliver
the mail.
Note that the simplest version of the message should be added first, and the fanciest version of the message should be added last.
As a variant, one can also add file attachments. To do so,
insert a multipart/mixed container around the multipart/alternative
message:
wrap_mail
~from_addr ~to_addrs ~subject
(wrap_parts
~content_type:("multipart/mixed", [])
[ wrap_parts
~content_type:("multipart/alternative", [])
[ wrap_attachment
~content_type:("text/plain", [])
(new Netmime.memory_mime_body s_plain);
wrap_attachment
~content_type:("text/html", [])
(new Netmime.memory_mime_body s_html)
];
wrap_attachment
~content_type:("audio/wav", [])
(new Netmime.file_mime_body "music.wav")
])
MHTML is an HTML document with attached resource files like images
or style sheets. For example, to have the HTML text s_html bundled
with an image and a style sheet, use:
wrap_mail
~from_addr ~to_addrs ~subject
(wrap_parts
~content_type:("multipart/related",
[ "type", Mimestring.mk_param "text/html" ])
[ wrap_attachment
~content_type:("text/html", [])
(new Netmime.memory_mime_body s_html);
wrap_attachment
~content_type:("image/gif", [])
~content_id:"img1"
(new Netmime.file_mime_body "my.gif")
wrap_attachment
~content_type:("text/css", [])
~content_id:"style1"
(new Netmime.file_mime_body "style.css")
])
Note the content_id arguments that assign names to the individual
parts. One can now refer to the parts from the HTML document by
cid URLs, e.g. cid:img1 points to the image in the second
part.
There is another mechanism using the Content-Location header to
resolve hyperlinks to message parts. See RFC 2557 for details.