ارسال مستقیم ایمیل از آردوینو

برای ارسال یک ایمیل از آردوینو، ما سشن تلنت(telnet) که در فصل قبل از آن استفاده کردیم را گسترش می دهیم. به جای اینکه به سختی، خصوصیت‌های(attributes) ایمیل خود را به کدهای شبکه(networking code) بنویسیم، قصد داریم یک کد پیشرفته تر را ایجاد کنیم. در ابتدا می خواهیم یک کلاسِ Email را ایجاد کنیم:

#ifndef __EMAIL__H_
#define __EMAIL__H_

class Email {
  String _from, _to, _subject, _body;
  
  public:
  
  Email(
    const String& from,
    const String& to,
    const String& subject,
    const String& body
  ) : _from(from), _to(to), _subject(subject), _body(body) {}

  const String& getFrom()    const { return _from; }
  const String& getTo()      const { return _to; }
  const String& getSubject() const { return _subject; }
  const String& getBody()    const { return _body; }
};

#endif

 این کدها، در آدرس زیر، در پوشه ی دانلودی قرار دارد:

Ethernet/Email/email.h

این کلاس چهار خصوصیت(attributes) مهم ایمیل را کپسوله سازی(نگهداری) می کند. اجزای این آدرس ایمیل، در زیر نشان داده شده است:

1. آدرس ایمیل فرستنده

2. موضوع(subject)

3. گیرنده(recipient)

4. متن ایمیل(message body)

ما تمام خصوصیت ها را بعنوان یک آبجکتِ رشته(String object) ذخیره می کنیم.


کمی صبر کنید! یک کلاسِ String ؟  بله. IDE آردوینو، حاوی یک کلاس رشته ای(String) کامل است. ویژگی های این کلاس به قدرت ++C یا جاوا نیست. اما این خیلی بهتر از سر و کله زدن با نشانگرهای کاراکتر(char) است. در ادامه، به روش استفاده از آنها می پردازیم.


 بقیه ی کلاس ایمیل، بسیار سر راست است. در کانستراکتور(سازنده)، ما تمام متغیرهای نمونه را مقداردهی اولیه(instance) می کنیم. و متدهایی برای هر خصوصیت تکی(single attribute) در اختیار داریم. حالا برای ارسال آبجکت های ایمیل(Email objects)، به یک کلاسِ SmtpService نیاز داریم:

#ifndef __SMTP_SERVICE__H_
#define __SMTP_SERVICE__H_

#include "email.h"

class SmtpService {
  boolean      _use_auth;
  IPAddress    _smtp_server;
  unsigned int _port;
  String       _username;
  String       _password;
 
  void read_response(EthernetClient& client) { 
    delay(4000);
    while (client.available()) {
      const char c = client.read();
      Serial.print(c);
    }
  }

  void send_line(EthernetClient& client, String line) { 
    const unsigned int MAX_LINE = 256;
    char buffer[MAX_LINE];
    line.toCharArray(buffer, MAX_LINE);
    Serial.println(buffer);
    client.println(buffer);
    read_response(client);
  }

  public:
  
  SmtpService( 
    const IPAddress&   smtp_server,
    const unsigned int port) : _use_auth(false),
                               _smtp_server(smtp_server), 
                               _port(port) { }
                               
  SmtpService( 
    const IPAddress&   smtp_server,
    const unsigned int port,
    const String&      username,
    const String&      password) : _use_auth(true),
                                   _smtp_server(smtp_server), 
                                   _port(port),
                                   _username(username),
                                   _password(password) { }
                               
  void send_email(const Email& email) { 
    EthernetClient client;
    Serial.print("Connecting...");
  
    if (client.connect(_smtp_server, _port) <= 0) {
      Serial.println("connection failed.");
    } else {
      Serial.println("connected.");
      read_response(client);
      if (!_use_auth) { 
        Serial.println("Using no authentication.");
        send_line(client, "helo");
      }
      else {
        Serial.println("Using authentication.");
        send_line(client, "ehlo");
        send_line(client, "auth login");
        send_line(client, _username);
        send_line(client, _password);
      }
      send_line(
        client,
        "mail from: <" + email.getFrom() + ">"
      );
      send_line(
        client,
        "rcpt to: <" + email.getTo() + ">"
      );
      send_line(client, "data");
      send_line(client, "from: " + email.getFrom());
      send_line(client, "to: " + email.getTo());
      send_line(client, "subject: " + email.getSubject());
      send_line(client, "");
      send_line(client, email.getBody());
      send_line(client, ".");
      send_line(client, "quit");    
      client.println("Disconnecting.");
      client.stop();
    }
  }
};

#endif

 این کد، در فایل های دانلودی زیر قرار دارد:

Ethernet/Email/smtp_service.h

می دانیم که این کدها زیاد هستند اما گام به گام آنها را توضیح خواهیم داد. ابتدا، باید بگوییم که کلاس SmtpService ،آدرس آی پی(IP) و پورت سرور SMTP را کپسوله سازی( یا محافظت و بسته بندی) می کند. این خصوصیت ها در هر موردی(in any case) ضروری هستند.

علاوه بر این، ما یک نام کاربری(username) و یک پسورد(password) را در مواردی که می خواهیم از یک کانکشن احراز هویت استفاده کنیم،  ذخیره می کنیم. برای ارتباط با یک سرور SMTP، باید پاسخ های آن را قرائت کنیم و این کار را با استفاده از متد read_response در خط شماره 13 (از کدهایی بالایی) انجام داده ایم.

این متد، چهار ثانیه صبر می کند(سرورهای SMTP معمولاً خیلی مشغول هستند، زیرا باید هرزنامه های زیادی را ارسال کنند)، آنگاه تمام داده های ارسال شده توسط سرور را قرائت کرده و آن را برای فرایند دیباگ کردن، در پورت سریال، بعنوان خروجی قرار می دهد.


قبل از اینکه بتوانیم پاسخ ها را پردازش کنیم، باید درخواست ها را ارسال کنیم. دستور send_line که در خط شماره 21 شروع می شود، یک دستور خاص را به یک سرورِ SMTP ارسال می کند. ما باید اتصال را به عنوان یک نمونه از تابع ()EthernetClient به سرور منتقل کنیم. و خط کدی که می خواهیم ارسال کنیم، باید یک آبجکتِ رشته ای(a String object) باشد.


 برای ارسال داده هایی که در یک آبجکت رشته ای( String object) ذخیره شده اند، ما نیاز داریم به (کلید) داده های کاراکتری که به آن(آبجکت) اشاره دارد، دسترسی داشته باشیم.

 برای (دوباره) به دست آوردن این اطلاعات، می‌توانیم از متدهای toCharArray یا getBytes استفاده کنیم. این دو متد، اشاره گر را، به (ابتدای) بافر(buffer) داخلیِ رشته بر‌نمی‌گردانند. به جای آن، از ما انتظار دارند که یک آرایه char که به اندازه ی کافی بزرگ باشد، و اندازه ی آن را ارائه دهیم. علت اینکه  چرا ما، قبل از اینکه محتوای خط ها را در بافر(buffer)، کپی کنیم، آن را بعنوان خروجی در پورت های سریال و اترنت(Ethernet) کپی می کنیم، همین است. پس از اینکه ما داده ها را ارسال کردیم، پاسخ سرور را قرائت می کنیم و آن را در پورت سریال چاپ می کنیم.

 در اینجا دو کانستراکتور داریم. اولین کانستراکتور در خط شماره 32 وجود دارد که منتظر آدرس IP سرور SMTP و پورت آن است.  اگر از آن استفاده کنیم، کلاس SmtpService فرض می کند که ما از احراز هویت استفاده نمی کنیم. برای احراز هویت در برابر سرویس SMTP با استفاده از یک نام کاربری(username) و پسورد(password)، باید از کانستراکتور دوم که در خط 38 شروع می شود، استفاده کنیم. علاوه بر آدرسِ IP سرورِ SMTP، و پورت آن، انتظار می رود که نام کاربری و پسورد، با Base64 رمزگذاری شود.

متد send_email بزرگترین قطعه کدی است که در کلاس ما وجود دارد؛ اما بسیار ساده است. این متد، از سشن telnet تقلید می کند. تنها چیزی که ارزش بحث کردن دارد، در خط شماره 57 وجود دارد. در خط 57، ما بررسی می کنیم که آیا اطلاعات احراز هویت(authentication)، در کانستراکتور مذکور ارائه شده است یا نه. اگر ارائه نشده باشد، ما پیغام HELO را ارسال می کنیم. اما اگر اطلاعات احراز هویت، ارائه شده باشد، ما پیغام EHLO و اطلاعات احراز هویت مربوطه را ارسال می کنیم. اکنون اجازه دهید با استفاده از کلاس های خود، برای ارسال یک ایمیل واقعی استفاده کنیم:

مثال شماره 6

1  #include <SPI.h>
-   #include <Ethernet.h>
-   #include "smtp_service.h"
-
5   const unsigned int SMTP_PORT = 2525;
-   const unsigned int BAUD_RATE = 9600;
-   const String USERNAME = "bm90bXl1c2VybmFtZQ=="; // Encoded in Base64.
-   const String PASSWORD = "bm90bXlwYXNzd29yZA=="; // Encoded in Base64.
-
10  byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
-    IPAddress my_ip(192, 168, 2, 120);
-
-   // Insert IP address of your SMTP server below!
-   IPAddress smtp_server(0, 0, 0, 0);
15
-   SmtpService smtp_service(smtp_server, SMTP_PORT, USERNAME, PASSWORD);
-
-   void setup() {
-   Ethernet.begin(mac, my_ip);
20  Serial.begin(BAUD_RATE);
-   delay(1000);
-   Email email(
-    "این آدرس ایمیل توسط spambots حفاظت می شود. برای دیدن شما نیاز به جاوا اسکریپت دارید",
-    "این آدرس ایمیل توسط spambots حفاظت می شود. برای دیدن شما نیاز به جاوا اسکریپت دارید",
25  "Yet another subject",
-    "Yet another body"
-  );
-   smtp_service.send_email(email);
-   }
30
-  void loop() {}

برای دانلود کدهای بالا، بدون اعداد شمارش گر، اینجا کلیک کنید.

در ین کدها، چیزهای جدیدی وجود ندارد. ما در ابتدا چد ثابت(constant) را برای پورت SMTP و مک آدرس(MAC address) و username و password تعریف می کنیم؛  سپس ما یک نمونه(instance) از  کلاسSmtpService ایجاد می کنیم و در تابع setup شیلد اترنت و پورت سریال را مقدار دهی اولیه(instance) می کنیم؛ سپس چند ثانیه صبر می کنیم تا همه چیز حل شود.

در خط 22، یک آبجکت Email جدید ایجاد می کنیم و آن را به متد send_email پاس می دهیم. تصویر 28، که در صفحه 194 از کتاب(در اول مقاله ی بعدی) قرار دارد،؛ یک سشن SMTP را در آردوینو، را در عمل نشان می دهد(که شامل احراز هویت هم می شود. اکنون ما می دانیم که چگونه با استفاده از یک آردوینو، ایمیل ارسال کنیم؛ اما برای ایجاد دزدگیر خود، باید چیزهای بیشتری در مورد تشخیص حرکت، یاد بگیریم.

 

برای نظردهی، در سایت عضو شوید یا به آن وارد شوید!

ستاره غیر فعالستاره غیر فعالستاره غیر فعالستاره غیر فعالستاره غیر فعال