1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 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 179 180 181 182 183 184 185 186 187 188 189 190 191
|
--
-- This file contains examples on how IMAPFilter can be extended using
-- the Lua programming language.
--
-- IMAPFilter can be detached from the controlling terminal and run in
-- the background as a system daemon.
--
-- The auxiliary function become_daemon() is supplied for convenience.
-- The following example puts imapfilter in the background and runs
-- endlessly, executing the commands in the forever() function and
-- sleeping for 600 seconds between intervals:
function forever()
results = myaccount.mymailbox:is_old()
results:move_messages(myaccount.myothermailbox)
end
become_daemon(600, forever)
-- The previous example uses polling in order to search specific messages and
-- process them. Another more efficient alternative is using the IMAP IDLE
-- extension. This is implemented by the enter_idle() method, which waits for
-- a notification by the server when new messages arrive in the monitored
-- mailbox.
while true do
myaccount.mymailbox:enter_idle()
results = myaccount.mymailbox:is_unseen()
results:move_messages(myaccount.myothermailbox)
end
-- The previous example can be further improved to consider whether new
-- messages arrived while filtering took place, and also somewhat work on
-- servers that have no IDLE support.
function custom_idle(mbox)
if #mbox:is_unseen() == 0 then
if not mbox:enter_idle() then
sleep(300)
end
end
end
while true do
custom_idle(myaccount.mymailbox)
results = myaccount.mymailbox:is_unseen()
results:move_messages(myaccount.myothermailbox)
end
-- IMAPFilter can take advantage of all those filtering utilities that
-- are available and use a wide range of heuristic tests, text analysis,
-- internet-based real-time blacklists, advanced learning algorithms,
-- etc. to classify mail. IMAPFilter can pipe a message to a program
-- and act on the message based on the program's exit status.
--
-- The auxiliary function pipe_to() is supplied for convenience. For
-- example if there was a utility named "bayesian-spam-filter", which
-- returned 1 when it considered the message "spam" and 0 otherwise:
all = myaccount.mymailbox:select_all()
results = Set {}
for _, mesg in ipairs(all) do
mbox, uid = table.unpack(mesg)
text = mbox[uid]:fetch_message()
if (pipe_to('bayesian-spam-filter', text) == 1) then
table.insert(results, mesg)
end
end
results:delete_messages()
-- One might want to run the bayesian filter only in those parts (attachments)
-- of the message that are of type text/plain and smaller than 1024 bytes.
-- This is possible using the fetch_structure() and fetch_part() functions:
all = myaccount.mymailbox:select_all()
results = Set {}
for _, mesg in ipairs(all) do
mbox, uid = table.unpack(mesg)
structure = mbox[uid]:fetch_structure()
for partid, partinf in pairs(structure) do
if partinf.type:lower() == 'text/plain' and partinf.size < 1024 then
part = mbox[uid]:fetch_part(partid)
if (pipe_to('bayesian-spam-filter', part) == 1) then
table.insert(results, mesg)
break
end
end
end
end
results:delete_messages()
-- Messages can be appended to a mailbox. One can fetch a message from a
-- mailbox, optionally process it, and then upload it to the same or different
-- mailbox, at the same or different mail servers. In the following example a
-- header field is added to all messages, and the processed messages are then
-- appended to a different mailbox.
all = myaccount.mymailbox:select_all()
for _, mesg in ipairs(all) do
mbox, uid = table.unpack(mesg)
header = mbox[uid]:fetch_header()
body = mbox[uid]:fetch_body()
message = header:gsub('[\r\n]+$', '\r\n') ..
'My-Header: My-Content\r\n' .. '\r\n' .. body
myaccount.myothermaibox:append_message(message)
end
-- Passwords could be extracted during execution time from an encrypted
-- password vault. Here's an example using pass.
status, password = pipe_from('pass Email/imap1.mail.server')
password = password:gsub('[\r\n]', '')
account1 = IMAP {
server = 'imap1.mail.server',
username = 'user1',
password = password
}
-- Normally when there's a problem, such as network failure to receive data
-- from or send data to the IMAP server, an error is raised, IMAPFilter stops
-- execution of the user's config, and quits.
--
-- In previous versions, IMAPFilter had an option to enable automatic recovery,
-- in which case it tried to reconnect, repeat the last IMAP command, and then
-- continue execution of the user's config.
--
-- Recently, this functionality was replaced by a new, more advanced, robust,
-- and flexible mechanism, where recovery can be fully controlled by the user,
-- using the auxiliary recover() function.
--
-- This example shows that set of commands can be grouped together in a
-- function, and if there's an error, the function will be re-executed from
-- start, once a connection has been re-established with the server:
function commands()
results = myaccount.mymailbox:is_old()
results:move_messages(myaccount.myothermailbox)
end
recover(commands)
-- When there are multiple accounts, where a series of actions are taking place
-- repeatedly, recovery can be controlled in such a way, that the rest of the
-- accounts commands are still processed, and the failure of a single account,
-- doesn't block the rest:
function commands1()
results = myaccount.mymailbox:is_old()
results:move_messages(myaccount.myothermailbox)
end
function commands2()
results2 = myaccount2.mymailbox2:is_seen()
results2:delete_messages()
end
while true do
recover(commands1, 4)
recover(commands2, 2)
end
-- It is also possible to handle the error captured during failure, or even
-- further process the returned values of the function executed:
function commands1()
results = myaccount.mymailbox:is_old()
results:move_messages(myaccount.myothermailbox)
end
function commands2()
return myaccount2.mymailbox2:is_seen()
end
success, errormsg = recover(commands1, 5)
if not success then print(errormsg) end
success2, results2 = recover(commands2)
if success2 then results2:delete_messages() end
|