diff options
Diffstat (limited to 'src/smtp.lua')
-rw-r--r-- | src/smtp.lua | 90 |
1 files changed, 65 insertions, 25 deletions
diff --git a/src/smtp.lua b/src/smtp.lua index ed8bd15..6ddeaae 100644 --- a/src/smtp.lua +++ b/src/smtp.lua | |||
@@ -20,6 +20,7 @@ DOMAIN = os.getenv("SERVER_NAME") or "localhost" | |||
20 | -- default time zone (means we don't know) | 20 | -- default time zone (means we don't know) |
21 | ZONE = "-0000" | 21 | ZONE = "-0000" |
22 | 22 | ||
23 | |||
23 | local function shift(a, b, c) | 24 | local function shift(a, b, c) |
24 | return b, c | 25 | return b, c |
25 | end | 26 | end |
@@ -29,31 +30,66 @@ function stuff() | |||
29 | return ltn12.filter.cycle(dot, 2) | 30 | return ltn12.filter.cycle(dot, 2) |
30 | end | 31 | end |
31 | 32 | ||
33 | --------------------------------------------------------------------------- | ||
34 | -- Low level SMTP API | ||
35 | ----------------------------------------------------------------------------- | ||
36 | local metat = { __index = {} } | ||
37 | |||
38 | function metat.__index:greet(domain) | ||
39 | socket.try(self.tp:check("2..")) | ||
40 | socket.try(self.tp:command("EHLO", domain or DOMAIN)) | ||
41 | return socket.try(self.tp:check("2..")) | ||
42 | end | ||
43 | |||
44 | function metat.__index:mail(from) | ||
45 | socket.try(self.tp:command("MAIL", "FROM:" .. from)) | ||
46 | return socket.try(self.tp:check("2..")) | ||
47 | end | ||
48 | |||
49 | function metat.__index:rcpt(to) | ||
50 | socket.try(self.tp:command("RCPT", "TO:" .. to)) | ||
51 | return socket.try(self.tp:check("2..")) | ||
52 | end | ||
53 | |||
54 | function metat.__index:data(src) | ||
55 | socket.try(self.tp:command("DATA")) | ||
56 | socket.try(self.tp:check("3..")) | ||
57 | socket.try(self.tp:source(src)) | ||
58 | socket.try(self.tp:send("\r\n.\r\n")) | ||
59 | return socket.try(self.tp:check("2..")) | ||
60 | end | ||
61 | |||
62 | function metat.__index:quit() | ||
63 | socket.try(self.tp:command("QUIT")) | ||
64 | return socket.try(self.tp:check("2..")) | ||
65 | end | ||
66 | |||
67 | function metat.__index:close() | ||
68 | return socket.try(self.tp:close()) | ||
69 | end | ||
70 | |||
32 | -- send message or throw an exception | 71 | -- send message or throw an exception |
33 | local function send_p(control, mailt) | 72 | function metat.__index:send(mailt) |
34 | socket.try(control:check("2..")) | 73 | self:mail(mailt.from) |
35 | socket.try(control:command("EHLO", mailt.domain or DOMAIN)) | ||
36 | socket.try(control:check("2..")) | ||
37 | socket.try(control:command("MAIL", "FROM:" .. mailt.from)) | ||
38 | socket.try(control:check("2..")) | ||
39 | if type(mailt.rcpt) == "table" then | 74 | if type(mailt.rcpt) == "table" then |
40 | for i,v in ipairs(mailt.rcpt) do | 75 | for i,v in ipairs(mailt.rcpt) do |
41 | socket.try(control:command("RCPT", "TO:" .. v)) | 76 | self:rcpt(v) |
42 | socket.try(control:check("2..")) | ||
43 | end | 77 | end |
44 | else | 78 | else |
45 | socket.try(control:command("RCPT", "TO:" .. mailt.rcpt)) | 79 | self:rcpt(mailt.rcpt) |
46 | socket.try(control:check("2..")) | ||
47 | end | 80 | end |
48 | socket.try(control:command("DATA")) | 81 | self:data(ltn12.source.chain(mailt.source, stuff())) |
49 | socket.try(control:check("3..")) | ||
50 | socket.try(control:source(ltn12.source.chain(mailt.source, stuff()))) | ||
51 | socket.try(control:send("\r\n.\r\n")) | ||
52 | socket.try(control:check("2..")) | ||
53 | socket.try(control:command("QUIT")) | ||
54 | socket.try(control:check("2..")) | ||
55 | end | 82 | end |
56 | 83 | ||
84 | function open(server, port) | ||
85 | local tp, error = socket.tp.connect(server or SERVER, port or PORT) | ||
86 | if not tp then return nil, error end | ||
87 | return setmetatable({tp = tp}, metat) | ||
88 | end | ||
89 | |||
90 | --------------------------------------------------------------------------- | ||
91 | -- Multipart message source | ||
92 | ----------------------------------------------------------------------------- | ||
57 | -- returns a hopefully unique mime boundary | 93 | -- returns a hopefully unique mime boundary |
58 | local seqno = 0 | 94 | local seqno = 0 |
59 | local function newboundary() | 95 | local function newboundary() |
@@ -147,13 +183,17 @@ function message(mesgt) | |||
147 | return function() return shift(coroutine.resume(co)) end | 183 | return function() return shift(coroutine.resume(co)) end |
148 | end | 184 | end |
149 | 185 | ||
150 | function send(mailt) | 186 | --------------------------------------------------------------------------- |
151 | local c, e = socket.tp.connect(mailt.server or SERVER, mailt.port or PORT) | 187 | -- High level SMTP API |
152 | if not c then return nil, e end | 188 | ----------------------------------------------------------------------------- |
153 | local s, e = pcall(send_p, c, mailt) | 189 | send = socket.protect(function(mailt) |
154 | c:close() | 190 | local server = mailt.server or SERVER |
155 | if s then return true | 191 | local port = mailt.port or PORT |
156 | else return nil, e end | 192 | local smtp = socket.try(open(server, port)) |
157 | end | 193 | smtp:greet(mailt.domain or DOMAIN) |
194 | smtp:send(mailt) | ||
195 | smtp:quit() | ||
196 | return smtp:close() | ||
197 | end) | ||
158 | 198 | ||
159 | return smtp | 199 | return smtp |