From 58096449c6044b7aade5cd41cfd71c6bec1d273d Mon Sep 17 00:00:00 2001
From: Diego Nehab
-The smtp.lua module provides functionality to send e-mail
+ The smtp.lua module provides functionality to send e-mail
messages. The implementation conforms to the Simple Mail Transfer Protocol,
RFC 2821.
-The other RFC of interest in this implementation is
-RFC 2822,
+Another RFC of interest is RFC 2822,
which governs the Internet Message Format.
+Multipart messages (those that contain attatchments) are part
+of the MIME standard, but described mainly
+in RFC
+2046
- In the description below, good understanding of LTN012, Filters
+sources and sinks and the MIME module is
+assumed. In fact, the SMTP module was the main reason for their
+creation.
MIME headers are represented as a Lua table in the form:
@@ -78,29 +85,56 @@ Note: MIME headers are independent of order. Therefore, there is no problem
in representing them in a Lua table.
+The following constants can be set to control the default behaviour of
+the SMTP module:
+
-socket.smtp.mail{
+smtp.send{
-Sends a message to a recipient list.
+Sends a message to a recipient list. Since sending messages is not as
+simple as downloading an URL from a FTP or HTTP server, this function
+doesn't have a simple interface. However, see the
+message source factory for
+a very powerful way to define the message contents.
-Rcpt is a Lua table with one entry for each recipient, or a string
+The sender is given by the e-mail address in the from field.
+Rcpt is a Lua table with one entry for each recipient e-mail
+address, or a string
in case there is just one recipient.
-The sender is given by the e-mail address from.
-The message is composed by the optional MIME Headers headers
-and text body. The message is sent using the server
-server.
+The contents of the message are given by a LTN12 source. Several
+arguments are optional:
+SMTP
-
+
+
+
+
+
+
from = string,
rcpt = string or string-table,
- body = string,
- headers = headers-table,
- server = string
+ source = LTN12 source,
+ [server = string],
+ [port = string]
+ [domain = string],
+ [step = LTN12 pump step],
}
+
@@ -108,6 +142,13 @@ If successful, the function returns 1. Otherwise, the function returns nil followed by an error message.
++Note: SMTP servers are can be very picky with the format of e-mail +addresses. To be safe, use only addresses of the form +"<fulano@tecgraf.puc-rio.br>" in the from and +rcpt arguments to the send function. In headers, e-mail +addresses can take whatever form you like.
+Big note: There is a good deal of misconception with the use of the destination address field headers, i.e., the 'To', 'Cc', @@ -117,11 +158,12 @@ exact opposite of what you expect.
-Only recipients specified in the recipient list will receive a copy of the +Only recipients specified in the rcpt list will receive a copy of the message. Each recipient of an SMTP mail message receives a copy of the -message body along with the headers, and nothing more. The headers are -considered as part of the message. The list of recipients is not -part of the message. +message body along with the headers, and nothing more. The headers +are part of the message and should be produced by the LTN12 +source function. The rcpt list is not +part of the message and will not be sent to anyone.
@@ -143,9 +185,9 @@ Copy") contains addresses of recipients of the message whose addresses are not t
-The LuaSocket mail function does not interpret the headers you -pass to, but it gives you full control over what is sent and to whom -it is sent: +The LuaSocket send function does not care or interpret the +headers you send, but it gives you full control over what is sent and +to whom it is sent:
+-- load the smtp support
+local smtp = require("smtp")
+
-- Connects to server "localhost" and sends a message to users
-- "fulano@tecgraf.puc-rio.br", "beltrano@tecgraf.puc-rio.br",
-- and "sicrano@tecgraf.puc-rio.br".
-- Note that "fulano" is the primary recipient, "beltrano" receives a
-- carbon copy and neither of them knows that "sicrano" received a blind
-- carbon copy of the message.
-headers = {
- to = "fulano@tecgraf.puc-rio.br",
- cc = "beltrano@tecgraf.puc-rio.br",
- subject = "LuaSocket test message"
-}
-
-from = "luasocket@tecgraf.puc-rio.br"
+from = "<luasocket@tecgraf.puc-rio.br>"
rcpt = {
- "fulano@tecgraf.puc-rio.br",
- "beltrano@tecgraf.puc-rio.br",
- "sicrano@tecgraf.puc-rio.br"
+ "<fulano@tecgraf.puc-rio.br>",
+ "<beltrano@tecgraf.puc-rio.br>",
+ "<sicrano@tecgraf.puc-rio.br>"
}
-body = "This is a test message. Please ignore."
-
-server = "localhost"
+mesgt = {
+ headers = {
+ to = "Fulano da Silva <fulano@tecgraf.puc-rio.br>",
+ cc = '"Beltrano F. Nunes" <beltrano@tecgraf.puc-rio.br>',
+ subject = "My first message"
+ }
+ body = "I hope this works. If it does, I can send you another 1000 copies."
+}
-r, e = socket.smtp.mail{
+r, e = smtp.send{
from = from,
rcpt = rcpt,
- headers = headers,
- body = body,
- server = server
+ source = smtp.message(mesgt)
+}
+
+
+
+
++smtp.message(mesgt) +
+ ++Returns a LTN12 source that sends an SMTP message body, possibly multipart +(arbitrarily deep). +
+ ++The only parameter of the function is a table describing the message. +Mesgt has the following form (notice the recursive structure): +
+ +++ ++
++ +mesgt = {
+ headers = header-table,
+ body = LTN12 source or string or +multipart-mesgt
+}
+
+multipart-mesgt = {
+ preamble = string
+ [1] = mesgt,
+ [2] = mesgt,
+ ...
+ [n] = mesgt,
+ epilogue = string,
+}
+
+For a simple message, all that is needed is a set of headers +and the body. The message body can be given as a string +or as a LTN12 source. For multipart messages, the body is a table that +recursively defines each part as an independent message, plus a preamble +and an epilogue. +
+ ++The function returns an LTN12 source that produces the message contents as +defined by mesgt. Hopefuly, the following example will make +things clear. When in doubt, refer to the appropriate RFC as listed in the +introduction.
+ +
+-- load the smtp support and its friends
+local smtp = require("smtp")
+local mime = require("mime")
+local ltn12 = require("ltn12")
+
+-- creates a source to send a message with two parts. The first part is
+-- plain text, the second part is a PNG image, encoded as base64.
+source = smtp.message{
+ headers = {
+ -- Remember that headers are *ignored* by smtp.send.
+ from = "Sicrano de Oliveira <sicrano@tecgraf.puc-rio.br>",
+ to = "Fulano da Silva <fulano@tecgraf.puc-rio.br>",
+ subject = "Here is a message with attachments"
+ },
+ body = {
+ preamble = "If your client doesn't understand attachments, \r\n" ..
+ "it will still display the preamble and the epilogue.\r\n",
+ "Preamble might show up even in a MIME enabled client.",
+ -- first part: no headers means plain text, us-ascii.
+ -- The mime.eol low-level filter normalizes end-of-line markers.
+ [1] = {
+ body = mime.eol(0, [[
+ Lines in a message body should always end with CRLF.
+ The smtp module will *NOT* perform translation. It will
+ perform necessary stuffing or '.' characters, though.
+ ]])
+ },
+ -- second part: headers describe content to be a png image,
+ -- sent under the base64 transfer content encoding.
+ -- notice that nothing happens until the message is actually sent.
+ -- small chunks are loaded into memory right before transmission and
+ -- translation happens on the fly.
+ [2] = {
+ headers = {
+ ["content-type"] = 'image/png; name="image.png"',
+ ["content-disposition"] = 'attachment; filename="image.png"',
+ ["content-description"] = 'a beautiful image',
+ ["content-transfer-encoding"] = "BASE64"
+ },
+ body = ltn12.source.chain(
+ ltn12.source.file(io.open("image.png", "rb")),
+ ltn12.filter.chain(
+ mime.encode("base64"),
+ mime.wrap()
+ )
+ )
+ },
+ epilogue = "This might also show up, but after the attachments"
+ }
+}
+
+-- finally send it
+r, e = smtp.send{
+ from = "<sicrano@tecgraf.puc-rio.br>",
+ rcpt = "<fulano@tecgraf.puc-rio.br>",
+ source = source,
}
--
cgit v1.2.3-55-g6feb