Skip to content

Commit b8efb2f

Browse files
committed
Import original code
1 parent d75eded commit b8efb2f

File tree

5 files changed

+394
-0
lines changed

5 files changed

+394
-0
lines changed

Mail.cpp

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#include "Mail.h"
2+
3+
Mail::Mail() {
4+
_from = NULL;
5+
_replyTo = NULL;
6+
memset(_recipients, NULL, sizeof(_recipients));
7+
memset(_recipientTypes, 0, sizeof(_recipientTypes));
8+
_recipientCount = 0;
9+
_subject = NULL;
10+
_body = NULL;
11+
}
12+
13+
void Mail::from(char *from) {
14+
_from = from;
15+
}
16+
17+
void Mail::replyTo(char *replyTo) {
18+
_replyTo = replyTo;
19+
}
20+
21+
void Mail::to(char *to) {
22+
addRecipient(TO, to);
23+
}
24+
25+
void Mail::cc(char *cc) {
26+
addRecipient(CC, cc);
27+
}
28+
29+
void Mail::bcc(char *bcc) {
30+
addRecipient(BCC, bcc);
31+
}
32+
33+
void Mail::subject(char *subject) {
34+
_subject = subject;
35+
}
36+
37+
void Mail::body(char *body) {
38+
_body = body;
39+
}
40+
41+
void Mail::addRecipient(recipient_t type, char* recipient) {
42+
if (_recipientCount == MAIL_LIB_MAX_RECIPIENTS) {
43+
return;
44+
}
45+
_recipientTypes[_recipientCount] = type;
46+
_recipients[_recipientCount] = recipient;
47+
_recipientCount++;
48+
}

Mail.h

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#ifndef MAIL_LIB_H
2+
#define MAIL_LIB_H
3+
4+
#include "Arduino.h"
5+
6+
#ifndef MAIL_LIB_MAX_RECIPIENTS
7+
#define MAIL_LIB_MAX_RECIPIENTS 16
8+
#endif
9+
10+
typedef enum {
11+
TO = 1,
12+
CC = 2,
13+
BCC = 3
14+
} recipient_t;
15+
16+
class Mail {
17+
public:
18+
Mail();
19+
20+
void from(char* from);
21+
void replyTo(char* replyTo);
22+
void to(char* to);
23+
void cc(char* cc);
24+
void bcc(char *bcc);
25+
void subject(char *subject);
26+
void body(char *body);
27+
28+
friend class SmtpClient;
29+
private:
30+
void addRecipient(recipient_t type, char* recipient);
31+
32+
char *_from;
33+
char *_replyTo;
34+
char *_recipients[MAIL_LIB_MAX_RECIPIENTS];
35+
recipient_t _recipientTypes[MAIL_LIB_MAX_RECIPIENTS];
36+
uint8_t _recipientCount;
37+
char *_subject;
38+
char *_body;
39+
};
40+
41+
#endif

README.md

+45
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,48 @@ This is an updated version from the one found originally at
66

77
Additions :
88
- api to query error conditions
9+
10+
11+
12+
13+
14+
SMTPClient
15+
==========
16+
17+
An Arduino library to send emails to an SMTP server. Supports sending emails from an Arduino to an unauthenticated
18+
SMTP server. This library supports sending email through Ethernet, however it should also work with WiFi, but this
19+
has not been tested.
20+
21+
Usage
22+
-----
23+
24+
`Client.h`, `Mail.h` and `SMTPClient.h` need to be imported.
25+
26+
#import <Client.h>
27+
#import <Mail.h>
28+
#import <SMTPClient.h>
29+
30+
An instance of `SMTPClient` needs to be created with the server hostname or IP and the port where the SMTP server is
31+
located as well as the `Client` instance that will be used to make the connection. If the port is omitted, it is
32+
defaulted to port 25. In the following example, the client is an `EthernetClient`, but a WiFi or other client could
33+
be specified.
34+
35+
byte ip[] = { 192, 168, 0, 125 };
36+
EthernetClient ethClient;
37+
SmtpClient client(&ethClient, ip);
38+
39+
To send an email, an instance of the `Mail` class needs to be creaed and methods called to populate the object.
40+
At a minimum, at least one recipient and a from address are required. A maximum of 16 destination addresses
41+
are supported, with them being any combination of To, Cc or Bcc.
42+
43+
Mail mail;
44+
mail.from("Some Sender <[email protected]>");
45+
mail.replyTo("[email protected]");
46+
mail.to("Someone <[email protected]>");
47+
mail.to("Someone Else <[email protected]>");
48+
mail.cc("Another <[email protected]>");
49+
mail.bcc("Secret <[email protected]>");
50+
mail.subject("Hello there");
51+
mail.body("I can send email from an Arduino!");
52+
client.send(&mail);
53+

SmtpClient.cpp

+223
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
#include "SmtpClient.h"
2+
#include "Client.h"
3+
#define SMTP_PORT 25
4+
#define ZERO_IP IPAddress(0, 0, 0, 0)
5+
#define TIMEOUT 10000
6+
#define CRLF "\r\n"
7+
8+
SmtpClient::SmtpClient(Client* client, char *server) : _client(client), _server(server), _serverIP(ZERO_IP), _port(SMTP_PORT) {
9+
}
10+
11+
SmtpClient::SmtpClient(Client* client, char *server, uint16_t port) : _client(client), _server(server), _serverIP(ZERO_IP), _port(port) {
12+
}
13+
14+
SmtpClient::SmtpClient(Client* client, IPAddress serverIP) : _client(client), _serverIP(serverIP), _server(""), _port(SMTP_PORT) {
15+
}
16+
17+
SmtpClient::SmtpClient(Client* client, IPAddress serverIP, uint16_t port) : _client(client), _serverIP(serverIP), _server(""), _port(port) {
18+
}
19+
20+
21+
int SmtpClient::send(Mail *mail) {
22+
int result = connect();
23+
if (!result) {
24+
_client->stop();
25+
return 0;
26+
}
27+
result = _send(mail);
28+
_client->stop();
29+
return result;
30+
}
31+
32+
int SmtpClient::_send(Mail *mail) {
33+
if (readStatus() != 220) {
34+
return 0;
35+
}
36+
if (helo() != 250) {
37+
return 0;
38+
}
39+
if (mailFrom(mail->_from) != 250) {
40+
return 0;
41+
}
42+
if (rcptTo(mail) != 250) {
43+
return 0;
44+
}
45+
if (data() != 354) {
46+
return 0;
47+
}
48+
headers(mail);
49+
body(mail->_body);
50+
if (finishBody() != 250) {
51+
return 0;
52+
}
53+
return 1;
54+
}
55+
56+
int SmtpClient::connect() {
57+
if (strlen(_server) > 0) {
58+
return _client->connect(_server, _port);
59+
} else {
60+
return _client->connect(_serverIP, _port);
61+
}
62+
}
63+
64+
int SmtpClient::helo() {
65+
_client->print("EHLO");
66+
_client->print(CRLF);
67+
int status = readStatus();
68+
if (status == 250) {
69+
return status;
70+
}
71+
// IF server doesn't understand EHLO, try HELO
72+
_client->print("HELO");
73+
_client->print(CRLF);
74+
return readStatus();
75+
}
76+
77+
int SmtpClient::mailFrom(char *from) {
78+
_client->print("MAIL FROM:");
79+
_client->print(from);
80+
_client->print(CRLF);
81+
return readStatus();
82+
}
83+
84+
int SmtpClient::rcptTo(Mail *mail) {
85+
int status;
86+
for (uint8_t i = 0; i < mail->_recipientCount; i++) {
87+
_client->print("RCPT TO:");
88+
_client->print(mail->_recipients[i]);
89+
_client->print(CRLF);
90+
91+
status = readStatus();
92+
if (status != 250) {
93+
break;
94+
}
95+
}
96+
return status;
97+
}
98+
99+
int SmtpClient::data() {
100+
_client->print("DATA ");
101+
_client->print(CRLF);
102+
return readStatus();
103+
}
104+
105+
void SmtpClient::headers(Mail *mail) {
106+
header("From:", mail->_from);
107+
if (mail->_replyTo) {
108+
header("Reply-To:", mail->_replyTo);
109+
}
110+
recipientHeader("To:", TO, mail);
111+
recipientHeader("Cc:", CC, mail);
112+
recipientHeader("Bcc:", BCC, mail);
113+
114+
header("Subject:", mail->_subject);
115+
}
116+
117+
void SmtpClient::header(char* header, char* value) {
118+
_client->print(header);
119+
_client->print(value);
120+
_client->print(CRLF);
121+
}
122+
123+
void SmtpClient::recipientHeader(char* header, recipient_t type, Mail *mail) {
124+
int first = 1;
125+
for (int i = 0; i < mail->_recipientCount; i++) {
126+
if (mail->_recipientTypes[i] == type) {
127+
if (first) {
128+
_client->print(header);
129+
first = 0;
130+
} else {
131+
_client->print(',');
132+
}
133+
_client->print(mail->_recipients[i]);
134+
}
135+
}
136+
if (!first) {
137+
_client->print(CRLF);
138+
}
139+
}
140+
141+
void SmtpClient::body(char *body) {
142+
int cr = 0;
143+
int lf = 0;
144+
145+
while(*body != '\0') {
146+
if (cr && lf && *body == '.') {
147+
// Add a second period to escapt the newline/period
148+
_client->print('.');
149+
150+
}
151+
if (cr && *body == '\n') {
152+
lf = 1;
153+
} else if (*body == '\r') {
154+
cr = 1;
155+
lf = 0;
156+
} else {
157+
cr = lf = 0;
158+
}
159+
_client->print((char) *body++);
160+
}
161+
}
162+
163+
int SmtpClient::finishBody() {
164+
_client->print(CRLF);
165+
_client->print('.');
166+
_client->print(CRLF);
167+
return readStatus();
168+
}
169+
170+
int SmtpClient::readStatus() {
171+
char line[4];
172+
int result;
173+
while(true) {
174+
result = readLine(line, 4);
175+
if (result >= 4 && (line[3] == '-')) {
176+
// Multiline result
177+
continue;
178+
}
179+
break;
180+
}
181+
182+
if (result < 3) {
183+
return 0;
184+
}
185+
186+
char st[4];
187+
strncpy(st, line, 3);
188+
st[3] = '\0';
189+
return atoi(st);
190+
}
191+
192+
int SmtpClient::readLine(char *line, int maxLen) {
193+
long start = millis();
194+
int count = 0;
195+
int cr = 0;
196+
while (true) {
197+
long now = millis();
198+
if (now < start || now - start > TIMEOUT) {
199+
return 0;
200+
}
201+
int c = _client->read();
202+
if (c != -1) {
203+
if (count < maxLen) {
204+
line[count++] = c;
205+
}
206+
if (cr && c == '\n') {
207+
break;
208+
}
209+
if (c == '\r') {
210+
cr = 1;
211+
continue;
212+
} else {
213+
cr = 0;
214+
}
215+
}
216+
}
217+
if (count == maxLen - 1) {
218+
line[count - 1] = '\0';
219+
} else {
220+
line[count] = '\0';
221+
}
222+
return count;
223+
}

0 commit comments

Comments
 (0)