aboutsummaryrefslogtreecommitdiff
path: root/src/smtp.lua
diff options
context:
space:
mode:
Diffstat (limited to 'src/smtp.lua')
-rw-r--r--src/smtp.lua90
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)
21ZONE = "-0000" 21ZONE = "-0000"
22 22
23
23local function shift(a, b, c) 24local function shift(a, b, c)
24 return b, c 25 return b, c
25end 26end
@@ -29,31 +30,66 @@ function stuff()
29 return ltn12.filter.cycle(dot, 2) 30 return ltn12.filter.cycle(dot, 2)
30end 31end
31 32
33---------------------------------------------------------------------------
34-- Low level SMTP API
35-----------------------------------------------------------------------------
36local metat = { __index = {} }
37
38function 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.."))
42end
43
44function metat.__index:mail(from)
45 socket.try(self.tp:command("MAIL", "FROM:" .. from))
46 return socket.try(self.tp:check("2.."))
47end
48
49function metat.__index:rcpt(to)
50 socket.try(self.tp:command("RCPT", "TO:" .. to))
51 return socket.try(self.tp:check("2.."))
52end
53
54function 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.."))
60end
61
62function metat.__index:quit()
63 socket.try(self.tp:command("QUIT"))
64 return socket.try(self.tp:check("2.."))
65end
66
67function metat.__index:close()
68 return socket.try(self.tp:close())
69end
70
32-- send message or throw an exception 71-- send message or throw an exception
33local function send_p(control, mailt) 72function 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.."))
55end 82end
56 83
84function 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)
88end
89
90---------------------------------------------------------------------------
91-- Multipart message source
92-----------------------------------------------------------------------------
57-- returns a hopefully unique mime boundary 93-- returns a hopefully unique mime boundary
58local seqno = 0 94local seqno = 0
59local function newboundary() 95local 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
148end 184end
149 185
150function 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) 189send = 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))
157end 193 smtp:greet(mailt.domain or DOMAIN)
194 smtp:send(mailt)
195 smtp:quit()
196 return smtp:close()
197end)
158 198
159return smtp 199return smtp