forked from mobizt/ESP-Mail-Client
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMailbox_Changes_Notification.ino
379 lines (308 loc) · 13.6 KB
/
Mailbox_Changes_Notification.ino
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
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
/**
* This example shows how to get notification in realtime when incoming message arrived and other mailbox changes.
*
* Email: [email protected]
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2022 mobizt
*
*/
/** For ESP8266, with BearSSL WiFi Client
* The memory reserved for completed valid SSL response from IMAP is 16 kbytes which
* may cause your device out of memory reset in case the memory
* allocation error.
*/
#include <Arduino.h>
#if defined(ESP32)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#else
// Other Client defined here
// To use custom Client, define ENABLE_CUSTOM_CLIENT in src/ESP_Mail_FS.h.
// See the example Custom_Client.ino for how to use.
#endif
#include <ESP_Mail_Client.h>
// To use only IMAP functions, you can exclude the SMTP from compilation, see ESP_Mail_FS.h.
#define WIFI_SSID "<ssid>"
#define WIFI_PASSWORD "<password>"
/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en
* and also https://accounts.google.com/b/0/DisplayUnlockCaptcha
*
* Some Gmail user still not able to sign in using account password even above options were set up,
* for this case, use "App Password" to sign in instead.
* About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en
*
* For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to
* https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc
*
* To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password
* and AUTHOR_EMAIL with your account email.
*/
/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */
#define IMAP_HOST "<host>"
/** The imap port e.g.
* 143 or esp_mail_imap_port_143
* 993 or esp_mail_imap_port_993
*/
#define IMAP_PORT 993
/* The log in credentials */
#define AUTHOR_EMAIL "<email>"
#define AUTHOR_PASSWORD "<password>"
/* Print the selected folder update info */
void printPollingStatus(IMAPSession &imap);
/* Callback function to get the Email reading status */
void imapCallback(IMAP_Status status);
/* Print the list of mailbox folders */
void printAllMailboxesInfo(IMAPSession &imap);
/* Print the selected folder info */
void printSelectedMailboxInfo(SelectedFolderInfo sFolder);
/* Print all messages from the message list */
void printMessages(MB_VECTOR<IMAP_MSG_Item> &msgItems, bool headerOnly);
/* Print all attachments info from the message */
void printAttacements(MB_VECTOR<IMAP_Attach_Item> &atts);
/* The IMAP Session object used for Email reading */
IMAPSession imap;
/* Declare the session config data */
ESP_Mail_Session session;
/* Setup the configuration for searching or fetching operation and its result */
IMAP_Config config;
void connectWiFi()
{
WiFi.disconnect();
Serial.print("Connecting to AP");
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(200);
}
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
Serial.println();
}
void setup()
{
Serial.begin(115200);
#if defined(ARDUINO_ARCH_SAMD)
while (!Serial)
;
Serial.println();
Serial.println("**** Custom built WiFiNINA firmware need to be installed.****\nTo install firmware, read the instruction here, https://github.com/mobizt/ESP-Mail-Client#install-custom-built-wifinina-firmware");
#endif
Serial.println();
/* Set the network reconnection option */
MailClient.networkReconnect(true);
connectWiFi();
/** Enable the debug via Serial port
* 0 for no debugging
* 1 for basic level debugging
*
* Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h
*/
imap.debug(1);
/* Set the callback function to get the reading results */
imap.callback(imapCallback);
/** In case the SD card/adapter was used for the file storagge, the SPI pins can be configure from
* MailClient.sdBegin function which may be different for ESP32 and ESP8266
* For ESP32, assign all of SPI pins
* MailClient.sdBegin(14,2,15,13)
* Which SCK = 14, MISO = 2, MOSI = 15 and SS = 13
* And for ESP8266, assign the CS pins of SPI port
* MailClient.sdBegin(15)
* Which pin 15 is the CS pin of SD card adapter
*/
/* Set the session config */
session.server.host_name = IMAP_HOST;
session.server.port = IMAP_PORT;
session.login.email = AUTHOR_EMAIL;
session.login.password = AUTHOR_PASSWORD;
session.time.ntp_server = F("pool.ntp.org,time.nist.gov");
session.time.gmt_offset = 3;
session.time.day_light_offset = 0;
/** Assign internet connection handler function
* in case of lost internet connection for re-listening the mailbox.
*/
session.network_connection_handler = connectWiFi;
/* Connect to server with the session and config */
if (!imap.connect(&session, &config))
return;
/* {Optional} */
printAllMailboxesInfo(imap);
/* Open or select the mailbox folder to read or search the message */
if (!imap.selectFolder(F("INBOX")))
return;
/* {Optional} */
printSelectedMailboxInfo(imap.selectedFolder());
}
void loop()
{
/* imap.connect and imap.selectFolder or imap.openFolder nedded to be called once prior to listen */
// Listen for mailbox changes
if (!imap.listen())
return;
// Check the changes
if (imap.folderChanged())
printPollingStatus(imap);
// To stop listen, use imap.stopListen(); and to listen again, call imap.listen()
}
void printPollingStatus(IMAPSession &imap)
{
/* Declare the selected folder info class to get the info of selected mailbox folder */
SelectedFolderInfo sFolder = imap.selectedFolder();
/* Show the mailbox info */
ESP_MAIL_PRINTF("\nMailbox status changed\n----------------------\nTotal Messages: %d\n", sFolder.msgCount());
if (sFolder.pollingStatus().type == imap_polling_status_type_new_message)
{
ESP_MAIL_PRINTF("New message %d, has been addedd, reading message...\n", (int)sFolder.pollingStatus().messageNum);
// if (sFolder.recentCount() > 0)
// ESP_MAIL_PRINTF("\nMesssage count which recent flag set: %d\n", sFolder.recentCount());
// we need to stop polling before do anything
imap.stopListen();
// Get the UID of new message and fetch
config.fetch.uid = imap.getUID(sFolder.pollingStatus().messageNum);
MailClient.readMail(&imap, false);
}
else if (sFolder.pollingStatus().type == imap_polling_status_type_remove_message)
ESP_MAIL_PRINTF("Message %d, has been removed\n\n", (int)sFolder.pollingStatus().messageNum);
else if (sFolder.pollingStatus().type == imap_polling_status_type_fetch_message)
ESP_MAIL_PRINTF("Message %d, has been fetched with the argument %s\n\n", (int)sFolder.pollingStatus().messageNum, sFolder.pollingStatus().argument.c_str());
}
void printSelectedMailboxInfo(IMAPSession &imap)
{
/* Declare the selected folder info class to get the info of selected mailbox folder */
SelectedFolderInfo sFolder = imap.selectedFolder();
/* Show the mailbox info */
ESP_MAIL_PRINTF("\nInfo of the selected folder\nTotal Messages: %d\n", sFolder.msgCount());
ESP_MAIL_PRINTF("Predicted next UID: %d\n", sFolder.nextUID());
ESP_MAIL_PRINTF("Unseen Message Index: %d\n", sFolder.unseenIndex());
for (size_t i = 0; i < sFolder.flagCount(); i++)
ESP_MAIL_PRINTF("%s%s%s", i == 0 ? "Flags: " : ", ", sFolder.flag(i).c_str(), i == sFolder.flagCount() - 1 ? "\n" : "");
}
/* Callback function to get the Email reading status */
void imapCallback(IMAP_Status status)
{
/* Print the current status */
Serial.println(status.info());
/* Show the result when reading finished */
if (status.success())
{
/* Print the result */
/* Get the message list from the message list data */
IMAP_MSG_List msgList = imap.data();
printMessages(msgList.msgItems, imap.headerOnly());
/* Clear all stored data in IMAPSession object */
imap.empty();
}
}
void printAllMailboxesInfo(IMAPSession &imap)
{
/* Declare the folder collection class to get the list of mailbox folders */
FoldersCollection folders;
/* Get the mailbox folders */
if (imap.getFolders(folders))
{
for (size_t i = 0; i < folders.size(); i++)
{
/* Iterate each folder info using the folder info item data */
FolderInfo folderInfo = folders.info(i);
ESP_MAIL_PRINTF("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : "");
}
}
}
void printSelectedMailboxInfo(SelectedFolderInfo sFolder)
{
/* Show the mailbox info */
ESP_MAIL_PRINTF("\nInfo of the selected folder\nTotal Messages: %d\n", sFolder.msgCount());
ESP_MAIL_PRINTF("Predicted next UID: %d\n", sFolder.nextUID());
ESP_MAIL_PRINTF("Unseen Message Index: %d\n", sFolder.unseenIndex());
for (size_t i = 0; i < sFolder.flagCount(); i++)
ESP_MAIL_PRINTF("%s%s%s", i == 0 ? "Flags: " : ", ", sFolder.flag(i).c_str(), i == sFolder.flagCount() - 1 ? "\n" : "");
}
void printAttacements(MB_VECTOR<IMAP_Attach_Item> &atts)
{
ESP_MAIL_PRINTF("Attachment: %d file(s)\n****************************\n", atts.size());
for (size_t j = 0; j < atts.size(); j++)
{
IMAP_Attach_Item att = atts[j];
/** att.type can be
* esp_mail_att_type_none or 0
* esp_mail_att_type_attachment or 1
* esp_mail_att_type_inline or 2
*/
ESP_MAIL_PRINTF("%d. Filename: %s, Name: %s, Size: %d, MIME: %s, Type: %s, Description: %s, Creation Date: %s\n", j + 1, att.filename, att.name, att.size, att.mime, att.type == esp_mail_att_type_attachment ? "attachment" : "inline", att.description, att.creationDate);
}
Serial.println();
}
void printMessages(MB_VECTOR<IMAP_MSG_Item> &msgItems, bool headerOnly)
{
for (size_t i = 0; i < msgItems.size(); i++)
{
/* Iterate to get each message data through the message item data */
IMAP_MSG_Item msg = msgItems[i];
Serial.println("****************************");
ESP_MAIL_PRINTF("Number: %d\n", msg.msgNo);
ESP_MAIL_PRINTF("UID: %d\n", msg.UID);
ESP_MAIL_PRINTF("Messsage-ID: %s\n", msg.ID);
ESP_MAIL_PRINTF("Flags: %s\n", msg.flags);
// The attachment may not detect in search because the multipart/mixed
// was not found in Content-Type header field.
ESP_MAIL_PRINTF("Attachment: %s\n", msg.hasAttachment ? "yes" : "no");
if (strlen(msg.acceptLang))
ESP_MAIL_PRINTF("Accept Language: %s\n", msg.acceptLang);
if (strlen(msg.contentLang))
ESP_MAIL_PRINTF("Content Language: %s\n", msg.contentLang);
if (strlen(msg.from))
ESP_MAIL_PRINTF("From: %s\n", msg.from);
if (strlen(msg.sender))
ESP_MAIL_PRINTF("Sender: %s\n", msg.sender);
if (strlen(msg.to))
ESP_MAIL_PRINTF("To: %s\n", msg.to);
if (strlen(msg.cc))
ESP_MAIL_PRINTF("CC: %s\n", msg.cc);
if (strlen(msg.date))
{
ESP_MAIL_PRINTF("Date: %s\n", msg.date);
ESP_MAIL_PRINTF("Timestamp: %d\n", (int)MailClient.Time.getTimestamp(msg.date));
}
if (strlen(msg.subject))
ESP_MAIL_PRINTF("Subject: %s\n", msg.subject);
if (strlen(msg.reply_to))
ESP_MAIL_PRINTF("Reply-To: %s\n", msg.reply_to);
if (strlen(msg.return_path))
ESP_MAIL_PRINTF("Return-Path: %s\n", msg.return_path);
if (strlen(msg.in_reply_to))
ESP_MAIL_PRINTF("In-Reply-To: %s\n", msg.in_reply_to);
if (strlen(msg.references))
ESP_MAIL_PRINTF("References: %s\n", msg.references);
if (strlen(msg.comments))
ESP_MAIL_PRINTF("Comments: %s\n", msg.comments);
if (strlen(msg.keywords))
ESP_MAIL_PRINTF("Keywords: %s\n", msg.keywords);
/* If the result contains the message info (Fetch mode) */
if (!headerOnly)
{
if (strlen(msg.text.content))
ESP_MAIL_PRINTF("Text Message: %s\n", msg.text.content);
if (strlen(msg.text.charSet))
ESP_MAIL_PRINTF("Text Message Charset: %s\n", msg.text.charSet);
if (strlen(msg.text.transfer_encoding))
ESP_MAIL_PRINTF("Text Message Transfer Encoding: %s\n", msg.text.transfer_encoding);
if (strlen(msg.html.content))
ESP_MAIL_PRINTF("HTML Message: %s\n", msg.html.content);
if (strlen(msg.html.charSet))
ESP_MAIL_PRINTF("HTML Message Charset: %s\n", msg.html.charSet);
if (strlen(msg.html.transfer_encoding))
ESP_MAIL_PRINTF("HTML Message Transfer Encoding: %s\n\n", msg.html.transfer_encoding);
if (msg.rfc822.size() > 0)
{
ESP_MAIL_PRINTF("RFC822 Messages: %d message(s)\n****************************\n", msg.rfc822.size());
printMessages(msg.rfc822, headerOnly);
}
}
Serial.println();
}
}