Tiny SMTP Client

Dependencies:   EthernetNetIf mbed

Files at this revision

API Documentation at this revision

Comitter:
okini3939
Date:
Wed Jul 27 15:09:04 2011 +0000
Child:
1:05064fe7ea1e
Commit message:

Changed in this revision

EthernetNetIf.lib Show annotated file Show diff for this revision Revisions of this file
TinySMTP.cpp Show annotated file Show diff for this revision Revisions of this file
TinySMTP.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EthernetNetIf.lib	Wed Jul 27 15:09:04 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/donatien/code/EthernetNetIf/#bc7df6da7589
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TinySMTP.cpp	Wed Jul 27 15:09:04 2011 +0000
@@ -0,0 +1,195 @@
+/*
+ * mbed Tiny SMTP Client
+ * Copyright (c) 2011 Hiroshi Suga
+ * Released under the MIT License: http://mbed.org/license/mit
+ */
+
+/** @file
+ * @brief Tiny SMTP Client
+ */
+
+#include "mbed.h"
+#include "EthernetNetIf.h"
+#include "TCPSocket.h"
+#include "DNSRequest.h"
+#include "TinySMTP.h"
+
+#define STATUS_NONE 0
+#define STATUS_READABLE 1
+#define STATUS_CONNECTED 2
+#define STATUS_ERROR 3
+#define STATUS_DISCONNECTED 4
+
+TCPSocket *smtp;
+volatile int tcp_status = 0, dns_status = 0;
+
+
+// Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+int base64enc(const char *input, unsigned int length, char *output, int outputlen) {
+  static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+  unsigned int c, c1, c2, c3;
+
+  if (outputlen < (((length-1)/3)+1)<<2) return -1;
+
+  for(unsigned int i = 0, j = 0; i<length; i+=3,j+=4) {
+    c1 = ((((unsigned char)*((unsigned char *)&input[i]))));
+    c2 = (length>i+1)?((((unsigned char)*((unsigned char *)&input[i+1])))):0;
+    c3 = (length>i+2)?((((unsigned char)*((unsigned char *)&input[i+2])))):0;
+
+    c = ((c1 & 0xFC) >> 2);
+    output[j+0] = base64[c];
+    c = ((c1 & 0x03) << 4) | ((c2 & 0xF0) >> 4);
+    output[j+1] = base64[c];
+    c = ((c2 & 0x0F) << 2) | ((c3 & 0xC0) >> 6);
+    output[j+2] = (length>i+1)?base64[c]:'=';
+    c = (c3 & 0x3F);
+    output[j+3] = (length>i+2)?base64[c]:'=';
+  }
+  output[(((length-1)/3)+1)<<2] = '\0';
+  return 0;
+}
+
+
+void isr_smtp (TCPSocketEvent e) {
+
+#ifdef DEBUG
+    printf("tcp(%d)\r\n", e);
+#endif
+    switch(e) {
+    case TCPSOCKET_READABLE: //Incoming data
+        tcp_status = STATUS_READABLE;
+        break;
+
+    case TCPSOCKET_CONNECTED:
+    case TCPSOCKET_WRITEABLE: //We can send data
+        tcp_status = STATUS_CONNECTED;
+        break;
+
+    case TCPSOCKET_CONTIMEOUT:
+    case TCPSOCKET_CONRST:
+    case TCPSOCKET_CONABRT:
+    case TCPSOCKET_ERROR:
+        tcp_status = STATUS_ERROR;
+        break;
+
+    case TCPSOCKET_DISCONNECTED:
+        tcp_status = STATUS_DISCONNECTED;
+        break;
+    }
+}
+
+int wait_smtp (int code) {
+    int i;
+    char buf[700];
+
+    // wait responce
+    for (i = 0; i < SMTP_TIMEOUT / 10; i ++) {
+        if (tcp_status != STATUS_CONNECTED) break;
+        Net::poll();
+        wait_ms(10);
+    }
+    if (tcp_status != STATUS_READABLE) return -1;
+    tcp_status = STATUS_CONNECTED;
+    // recv
+    i = smtp->recv(buf, sizeof(buf));
+    buf[i] = 0;
+#ifdef DEBUG
+    printf(buf);
+#endif
+
+    // check return code
+    if (atoi(buf) == code) return 0;
+
+    return -1;
+}
+
+void isr_dns (DNSReply r) {
+
+    if (DNS_FOUND) {
+        dns_status = 1;
+    } else {
+        dns_status = -1;
+    }
+}
+
+int sendmail (char *to, char *from, char *data, Host *host, char *user, char *pwd) {
+    TCPSocketErr err;
+    int i, ret = -1;
+
+    smtp = new TCPSocket;
+    tcp_status = STATUS_NONE;
+
+    smtp->setOnEvent(isr_smtp);
+
+    // connect
+    if (host->getIp().isNull()) {
+        DNSRequest dns;
+        dns_status = 0;
+        dns.setOnReply(isr_dns);
+        if (dns.resolve(host) != DNS_OK) goto exit;
+        for (i = 0; i < SMTP_TIMEOUT / 10; i ++) {
+            if (dns_status) break;
+            Net::poll();
+            wait_ms(10);
+        }
+        while (dns_status < 0) goto exit;
+    }
+    err = smtp->connect(*host);
+    if (err != TCPSOCKET_OK) goto exit;
+
+    // wait connect
+    for (i = 0; i < 1500; i ++) {
+        if (tcp_status != STATUS_NONE) break;
+        Net::poll();
+        wait_ms(10);
+    }
+    if (wait_smtp(220)) goto exit;
+
+    // send request
+    wait_ms(100);
+    smtp->send("EHLO mbed\r\n", 11);
+    if (wait_smtp(250)) goto exit;
+
+    if (user && pwd) {
+        // smtp auth
+        char tmp[80], buf[100];
+        int len;
+        snprintf(tmp, sizeof(tmp), "%s%c%s%c%s", user, 0, user, 0, pwd);
+        len = strlen(user) * 2 + strlen(pwd) + 2;
+        base64enc(tmp, len, buf, sizeof(buf));
+        smtp->send("AUTH PLAIN ", 11);
+        smtp->send(buf, strlen(buf));
+        smtp->send("\r\n", 2);
+        if (wait_smtp(235)) goto quit;
+    }
+
+    smtp->send("MAIL FROM: ", 11);
+    smtp->send(from, strlen(from));
+    smtp->send("\r\n", 2);
+    if (wait_smtp(250)) goto quit;
+
+    smtp->send("RCPT TO: ", 9);
+    smtp->send(to, strlen(to));
+    smtp->send("\r\n", 2);
+    if (wait_smtp(250)) goto quit;
+
+    smtp->send("DATA\r\n", 6);
+    if (wait_smtp(354)) goto quit;
+
+    // mail data
+    smtp->send(data, strlen(data));
+    smtp->send("\r\n.\r\n", 5);
+    if (wait_smtp(250)) goto quit;
+    ret = 0;
+
+quit:
+    smtp->send("QUIT\r\n", 6);
+    if (wait_smtp(221)) goto exit;
+
+exit:
+    smtp->resetOnEvent();
+    smtp->close();
+    delete smtp;
+
+    return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TinySMTP.h	Wed Jul 27 15:09:04 2011 +0000
@@ -0,0 +1,31 @@
+/*
+ * mbed Tiny SMTP Client
+ * Copyright (c) 2011 Hiroshi Suga
+ * Released under the MIT License: http://mbed.org/license/mit
+ */
+
+/** @file
+ * @brief Tiny SMTP Client
+ */
+
+#ifndef TinySMTP_h
+#define TinySMTP_h
+
+#define DEBUG
+
+#define SMTP_PORT 25
+#define SMTP_TIMEOUT 15000 // ms
+
+/** send mail
+ * @param to mail address
+ * @param from mail address
+ * @param data mail body
+ * @param host mail server
+ * @param data mail body
+ * @param user auth username (or NULL)
+ * @param pwd auth password (or NULL)
+ * @return 0:success, -1:failue
+ */
+int sendmail (char *to, char *from, char *data, Host *host, char *user, char *pwd);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Wed Jul 27 15:09:04 2011 +0000
@@ -0,0 +1,47 @@
+#include "mbed.h"
+#include "EthernetNetIf.h"
+#include "TCPSocket.h"
+#include "TinySMTP.h"
+
+#define SMTP "mail.domain.name"
+#define PORT 587 // or 25
+#define FROM "from@domain.name"
+#define TO "to@domain.name"
+#define USER "authuser"
+#define PWD "password"
+#define SUBJECT "mail test"
+#define BODY "TEST TEST"
+
+DigitalOut myled(LED1);
+Serial pc(USBTX, USBRX);
+EthernetNetIf eth;
+
+int main () {
+    EthernetErr ethErr;
+    Host host;
+    int r;
+    char data[500];
+
+    myled = 1;
+
+    strcpy(data, "From: " FROM "\r\nTo: " TO "\r\n");
+    strcat(data, "Subject: " SUBJECT "\r\n\r\n" BODY "\r\n");
+
+    ethErr = eth.setup();
+    if(ethErr) {
+        return -1;
+    }
+
+    host.setName(SMTP);
+    host.setPort(PORT);
+    r = sendmail(FROM, TO, data, &host, USER, PWD);
+
+    if (r) {
+        printf("error\r\n");
+    } else {
+        printf("sent\r\n");
+    }
+
+    myled = 0;
+    return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Wed Jul 27 15:09:04 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/63bcd7ba4912