Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ruanhaishen
Nodemcu Firmware
Commits
72f76744
Commit
72f76744
authored
Mar 12, 2015
by
AllAboutEE
Browse files
Working example of IMAP read email module.
parent
56aa4165
Changes
2
Show whitespace changes
Inline
Side-by-side
lua_examples/email/read_email_imap.lua
View file @
72f76744
---
---
-- @author Miguel (AllAboutEE.com)
-- @author Miguel (AllAboutEE.com)
-- @description Reads email via IMAP
-- @description This example will read the first email in your inbox using IMAP and
-- display it through serial. The email server must provided unecrypted access. The code
-- was tested with an AOL and Time Waraner cable email ccounts (GMail and other services who do
-- not support no SSL access will not work).
-- this could be your email (and it is in most cases even in you have a "username")
require
(
"imap"
)
require
(
"imap"
)
local
IMAP_USERNAME
=
"
my
email@domain.com"
local
IMAP_USERNAME
=
"email@domain.com"
local
IMAP_PASSWORD
=
"
myemail
password"
local
IMAP_PASSWORD
=
"password"
local
IMAP_SERVER
=
"imap.domain.com"
-- find out your unencrypted imap server and port
-- from your email provided i.e. google "[my email service] imap settings" for example
local
IMAP_SERVER
=
"imap.service.com"
local
IMAP_PORT
=
"143"
local
IMAP_PORT
=
"143"
local
IMAP_TAG
=
"t1"
local
IMAP_TAG
=
"t1"
-- You do not need to change this
local
IMAP_DEBUG
=
false
-- change to true if you would like to see the entire conversation between
-- the ESP8266 and IMAP server
local
SSID
=
"ssid"
local
SSID
=
"ssid"
local
SSID_PASSWORD
=
"
ssid
password"
local
SSID_PASSWORD
=
"password"
local
count
=
0
local
count
=
0
-- we will send several IMAP commands/requests, this variable helps keep track of which one to send
-- configure the ESP8266 as a station
wifi
.
setmode
(
wifi
.
STATION
)
wifi
.
setmode
(
wifi
.
STATION
)
wifi
.
sta
.
config
(
SSID
,
SSID_PASSWORD
)
wifi
.
sta
.
config
(
SSID
,
SSID_PASSWORD
)
wifi
.
sta
.
autoconnect
(
1
)
wifi
.
sta
.
autoconnect
(
1
)
-- create an unencrypted connection
local
imap_socket
=
net
.
createConnection
(
net
.
TCP
,
0
)
local
imap_socket
=
net
.
createConnection
(
net
.
TCP
,
0
)
---
-- @name setup
-- @description A call back function used to begin reading email
-- upon sucessfull connection to the IMAP server
function
setup
(
sck
)
function
setup
(
sck
)
-- Set the email user name and password, IMAP tag, and if debugging output is needed
imap
.
config
(
IMAP_USERNAME
,
imap
.
config
(
IMAP_USERNAME
,
IMAP_PASSWORD
,
IMAP_PASSWORD
,
IMAP_TAG
,
IMAP_TAG
,
sck
)
IMAP_DEBUG
)
imap
.
login
(
imap_socket
)
imap
.
login
(
sck
)
end
end
imap_socket
:
on
(
"connection"
,
setup
)
imap_socket
:
on
(
"connection"
,
setup
)
-- call setup() upon connection
imap_socket
:
connect
(
IMAP_PORT
,
IMAP_SERVER
)
imap_socket
:
connect
(
IMAP_PORT
,
IMAP_SERVER
)
-- connect to the IMAP server
local
subject
=
""
local
from
=
""
local
message
=
""
---
-- @name do_next
-- @description A call back function for a timer alarm used to check if the previous
-- IMAP command reply has been processed. If the IMAP reply has been processed
-- this function will call the next IMAP command function necessary to read the email
function
do_next
()
function
do_next
()
if
(
imap
.
receive_complete
()
==
true
)
then
-- Check if the IMAP reply was processed
print
(
"receive complete"
)
if
(
imap
.
response_processed
()
==
true
)
then
-- The IMAP reply was processed
if
(
count
==
0
)
then
if
(
count
==
0
)
then
print
(
"Examine:\r\n"
)
-- After logging in we need to select the email folder from which we wish to read
-- in this case the INBOX folder
imap
.
examine
(
imap_socket
,
"INBOX"
)
imap
.
examine
(
imap_socket
,
"INBOX"
)
count
=
count
+
1
count
=
count
+
1
elseif
(
count
==
1
)
then
elseif
(
count
==
1
)
then
imap
.
fetch_header
(
imap_socket
,
1
,
"SUBJECT"
)
-- After examining/selecting the INBOX folder we can begin to retrieve emails.
imap
.
fetch_header
(
imap_socket
,
imap
.
get_most_recent_num
(),
"SUBJECT"
)
-- Retrieve the SUBJECT of the first/newest email
count
=
count
+
1
count
=
count
+
1
elseif
(
count
==
2
)
then
elseif
(
count
==
2
)
then
imap
.
fetch_header
(
imap_socket
,
1
,
"FROM"
)
subject
=
imap
.
get_header
()
-- store the SUBJECT response in subject
imap
.
fetch_header
(
imap_socket
,
imap
.
get_most_recent_num
(),
"FROM"
)
-- Retrieve the FROM of the first/newest email
count
=
count
+
1
count
=
count
+
1
elseif
(
count
==
3
)
then
elseif
(
count
==
3
)
then
imap
.
fetch_body_plain_text
(
imap_socket
,
1
)
from
=
imap
.
get_header
()
-- store the FROM response in from
imap
.
fetch_body_plain_text
(
imap_socket
,
imap
.
get_most_recent_num
())
-- Retrieve the BODY of the first/newest email
count
=
count
+
1
count
=
count
+
1
elseif
(
count
==
4
)
then
elseif
(
count
==
4
)
then
imap
.
logout
(
imap_socket
)
body
=
imap
.
get_body
()
-- store the BODY response in body
imap
.
logout
(
imap_socket
)
-- Logout of the email account
count
=
count
+
1
count
=
count
+
1
else
else
print
(
"The body is: "
..
imap
.
get_body
())
-- display the email contents
tmr
.
stop
(
0
)
imap_socket
:
close
()
-- create patterns to strip away IMAP protocl text from actual message
collectgarbage
()
pattern1
=
"(\*.+\}\r\n)"
-- to remove "* n command (BODY[n] {n}"
pattern2
=
"(\r\n.+)"
-- to remove ") t1 OK command completed"
from
=
string.gsub
(
from
,
pattern1
,
""
)
from
=
string.gsub
(
from
,
pattern2
,
""
)
print
(
from
)
subject
=
string.gsub
(
subject
,
pattern1
,
""
)
subject
=
string.gsub
(
subject
,
pattern2
,
""
)
print
(
subject
)
body
=
string.gsub
(
body
,
pattern1
,
""
)
body
=
string.gsub
(
body
,
pattern2
,
""
)
print
(
"Message: "
..
body
)
tmr
.
stop
(
0
)
-- Stop the timer alarm
imap_socket
:
close
()
-- close the IMAP socket
collectgarbage
()
-- clean up
end
end
end
end
end
end
-- A timer alarm is sued to check if an IMAP reply has been processed
tmr
.
alarm
(
0
,
1000
,
1
,
do_next
)
tmr
.
alarm
(
0
,
1000
,
1
,
do_next
)
lua_modules/email/imap.lua
View file @
72f76744
---
-- IMPORTANT: run node.compile("imap.lua") after uploading this script
-- to create a compiled module. Then run file.remove("imap.lua")
-- @name imap
-- @description An IMAP 4rev1 module that can be used to read email.
-- Tested on NodeMCU 0.9.5 build 20150213.
-- @date March 12, 2015
-- @author Miguel
-- GitHub: https://github.com/AllAboutEE
-- YouTube: https://www.youtube.com/user/AllAboutEE
-- Website: http://AllAboutEE.com
--
-- Visit the following URLs to learn more about IMAP:
-- "How to test an IMAP server by using telnet" http://www.anta.net/misc/telnet-troubleshooting/imap.shtml
-- "RFC 2060 - Internet Message Access Protocol - Version 4rev1" http://www.faqs.org/rfcs/rfc2060.html
-------------------------------------------------------------------------------------------------------------
local
moduleName
=
...
local
moduleName
=
...
local
M
=
{}
local
M
=
{}
_G
[
moduleName
]
=
M
_G
[
moduleName
]
=
M
...
@@ -9,71 +25,180 @@ local SERVER = ""
...
@@ -9,71 +25,180 @@ local SERVER = ""
local
PORT
=
""
local
PORT
=
""
local
TAG
=
""
local
TAG
=
""
local
body
=
""
local
DEBUG
=
false
local
body
=
""
-- used to store an email's body / main text
local
header
=
""
-- used to store an email's last requested header field e.g. SUBJECT, FROM, DATA etc.
local
most_recent_num
=
1
-- used to store the latest/newest email number/id
local
receive_complete
=
false
function
M
.
receive_complete
()
local
response_processed
=
false
-- used to know if the last IMAP response has been processed
return
receive_complete
end
---
-- @name response_processed
-- @returns The response process status of the last IMAP command sent
function
M
.
response_processed
()
return
response_processed
end
---
-- @name display
-- @description A generic IMAP response processing function.
-- Can disply the IMAP response if DEBUG is set to true.
-- Sets the reponse processed variable to true when the string "complete"
-- is found in the IMAP reply/response
local
function
display
(
socket
,
response
)
local
function
display
(
socket
,
response
)
-- If debuggins is enabled print the IMAP response
if
(
DEBUG
)
then
print
(
response
)
print
(
response
)
end
-- Some IMAP responses are long enough that they will cause the display
-- function to be called several times. One thing is certain, IMAP will replay with
-- "<tag> OK <command> complete" when it's done sending data back.
if
(
string.match
(
response
,
'complete'
)
~=
nil
)
then
if
(
string.match
(
response
,
'complete'
)
~=
nil
)
then
re
ceive_complete
=
true
re
sponse_processed
=
true
end
end
end
end
function
M
.
config
(
username
,
password
,
tag
,
sk
)
---
-- @name config
-- @description Initiates the IMAP settings
function
M
.
config
(
username
,
password
,
tag
,
debug
)
USERNAME
=
username
USERNAME
=
username
PASSWORD
=
password
PASSWORD
=
password
TAG
=
tag
TAG
=
tag
DEBUG
=
debug
end
end
---
-- @name login
-- @descrpiton Logs into a new email session
function
M
.
login
(
socket
)
function
M
.
login
(
socket
)
receive_complete
=
false
response_processed
=
false
-- we are sending a new command
-- which means that the response for it has not been processed
socket
:
send
(
TAG
..
" LOGIN "
..
USERNAME
..
" "
..
PASSWORD
..
"
\r\n
"
)
socket
:
send
(
TAG
..
" LOGIN "
..
USERNAME
..
" "
..
PASSWORD
..
"
\r\n
"
)
socket
:
on
(
"receive"
,
display
)
socket
:
on
(
"receive"
,
display
)
end
end
---
-- @name get_most_recent_num
-- @returns The most recent email number. Should only be called after examine()
function
M
.
get_most_recent_num
()
return
most_recent_num
end
---
-- @name set_most_recent_num
-- @description Gets the most recent email number from the EXAMINE command.
-- i.e. if EXAMINE returns "* 4 EXISTS" this means that there are 4 emails,
-- so the latest/newest will be identified by the number 4
local
function
set_most_recent_num
(
socket
,
response
)
if
(
DEBUG
)
then
print
(
response
)
end
local
_
,
_
,
num
=
string.find
(
response
,
"([0-9]+) EXISTS(\.)"
)
-- the _ and _ keep the index of the string found
-- but we don't care about that.
if
(
num
~=
nil
)
then
most_recent_num
=
num
end
if
(
string.match
(
response
,
'complete'
)
~=
nil
)
then
response_processed
=
true
end
end
---
-- @name examine
-- @description IMAP examines the given mailbox/folder. Sends the IMAP EXAMINE command
function
M
.
examine
(
socket
,
mailbox
)
function
M
.
examine
(
socket
,
mailbox
)
re
ceive_complete
=
false
re
sponse_processed
=
false
socket
:
send
(
TAG
..
" EXAMINE "
..
mailbox
..
"
\r\n
"
)
socket
:
send
(
TAG
..
" EXAMINE "
..
mailbox
..
"
\r\n
"
)
socket
:
on
(
"receive"
,
display
)
socket
:
on
(
"receive"
,
set_most_recent_num
)
end
end
function
M
.
fetch_header
(
socket
,
msg_number
,
field
)
---
-- @name get_header
-- @returns The last fetched header field
function
M
.
get_header
()
return
header
end
---
-- @name set_header
-- @description Records the IMAP header field response in a variable
-- so that it may be read later
local
function
set_header
(
socket
,
response
)
if
(
DEBUG
)
then
print
(
response
)
end
header
=
header
..
response
if
(
string.match
(
response
,
'complete'
)
~=
nil
)
then
response_processed
=
true
end
end
receive_complete
=
false
---
-- @name fetch_header
-- @description Fetches an emails header field e.g. SUBJECT, FROM, DATE
-- @param socket The IMAP socket to use
-- @param msg_number The email number to read e.g. 1 will read fetch the latest/newest email
-- @param field A header field such as SUBJECT, FROM, or DATE
function
M
.
fetch_header
(
socket
,
msg_number
,
field
)
header
=
""
-- we are getting a new header so clear this variable
response_processed
=
false
socket
:
send
(
TAG
..
" FETCH "
..
msg_number
..
" BODY[HEADER.FIELDS ("
..
field
..
")]\r\n"
)
socket
:
send
(
TAG
..
" FETCH "
..
msg_number
..
" BODY[HEADER.FIELDS ("
..
field
..
")]\r\n"
)
socket
:
on
(
"receive"
,
display
)
socket
:
on
(
"receive"
,
set_header
)
end
end
---
-- @name get_body
-- @return The last email read's body
function
M
.
get_body
()
function
M
.
get_body
()
return
body
return
body
end
end
---
-- @name set_body
-- @description Records the IMAP body response in a variable
-- so that it may be read later
local
function
set_body
(
socket
,
response
)
local
function
set_body
(
socket
,
response
)
if
(
DEBUG
)
then
print
(
response
)
print
(
response
)
end
body
=
body
..
response
body
=
body
..
response
if
(
string.match
(
response
,
'complete'
)
~=
nil
)
then
if
(
string.match
(
response
,
'complete'
)
~=
nil
)
then
re
ceive_complete
=
true
re
sponse_processed
=
true
end
end
end
end
---
-- @name fetch_body_plain_text
-- @description Sends the IMAP command to fetch a plain text version of the email's body
-- @param socket The IMAP socket to use
-- @param msg_number The email number to obtain e.g. 1 will obtain the latest email
function
M
.
fetch_body_plain_text
(
socket
,
msg_number
)
function
M
.
fetch_body_plain_text
(
socket
,
msg_number
)
receive_complete
=
false
response_processed
=
false
body
=
""
body
=
""
-- clear the body variable since we'll be fetching a new email
socket
:
send
(
TAG
..
" FETCH "
..
msg_number
..
" BODY[1]\r\n"
)
socket
:
send
(
TAG
..
" FETCH "
..
msg_number
..
" BODY[1]\r\n"
)
socket
:
on
(
"receive"
,
set_body
)
socket
:
on
(
"receive"
,
set_body
)
end
end
---
-- @name logout
-- @description Sends the IMAP command to logout of the email session
function
M
.
logout
(
socket
)
function
M
.
logout
(
socket
)
re
ceive_complete
=
false
re
sponse_processed
=
false
socket
:
send
(
TAG
..
" LOGOUT\r\n"
)
socket
:
send
(
TAG
..
" LOGOUT\r\n"
)
socket
:
on
(
"receive"
,
display
)
socket
:
on
(
"receive"
,
display
)
end
end
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment