Отправка SMS, email из QLua, или C#

Автор записи: Дмитрий (Admin)

SMSОтправка SMS

Для того, чтобы программно отправлять SMS из QLua, или C#, для начала перейдите по этой ссылке. Вы попадете на сайт сервиса "SMS ЦЕНТР"
img-2015-07-03-21-36-09
Нажав на кнопку "РЕГИСТРАЦИЯ В СЕРВИСЕ", Вы увидите форму регистрации, заполните все поля, обязательно укажите свой телефон.
SMS форма регистрации
Нажмите на кнопку "Зарегистрироваться".
Затем нажмите на кнопку "Мой кабинет":
img-2015-07-03-21-50-35
Далее, нажмите на ссылку "Подтвердить номер", затем на кнопку "Получить SMS", Вам на телефон придет SMS с кодом, введите его в поле слева от кнопки, и нажмите ниже кнопку "Подтвердить номер"
img-2015-07-03-21-57-10
После этого на Вашем счету появятся 15 подарочных рублей для тестирования.
Цены на отправку SMS вы можете посмотреть в разделе "Мой кабинет".
На этом настройку на данном сайте можно считать завершенной.

Для использования данного сервиса в QLua нужно скачать данный архив, извлечь из него 3 папки: "lua", "mime", "socket". И поместить их в корневой каталог терминала QUIK (туда, где файл info.exe).

Пример отправки SMS из QLua
1
2
3
4
5
6
7
8
9
10
11
12
http = require('socket.http');
 
login = "MyLogin";           -- Ваш логин на сайте smsc.ru
password = "MyPassword";     -- Ваш пароль на сайте smsc.ru
phone = "79999999999";       -- Ваш номер телефона
msg = "Текст сообщения";
 
function main()
   message(tostring(http.request ("http://smsc.ru/sys/send.php?login="..login.."&psw="..password.."&phones="..phone.."&mes="..msg)));
end;
 
-- Если Вы нигде не ошиблись, то получите SMS на телефон от "SMSC.RU" и сообщение в терминале вида: "OK - 1 SMS, ID - 1"

Для отправки SMS из C# перейдите по данной ссылке и скачайте первый файл "smsc_api.cs"
img-2015-07-06-19-34-37
Положите его в папку с Вашим проектом C# (там, где папка bin) и добавьте его в проект, нажав правой кнопкой мыши по названию проекта, перейдя по пути: "Добавить" -> "Существующий элемент...", выбрав данный файл в папке проекта и нажав кнопку добавить.
img-2015-07-06-19-39-50

Далее, нажмите правой кнопкой мыши по ссылке "References" Вашего проекта и выберите "Добавить ссылку...".
img-2015-07-06-19-46-35
В открывшемся окне найдите "System.Web", поставьте галочку слева от него и нажмите на кнопку "ОК".
img-2015-07-06-19-48-44
Теперь необходимый функционал подключен к проекту!

Пример отправки SMS из C#
На форму добавьте кнопку, сделайте по ней двойной щелчок мышкой и в созданную функцию добавьте следующий код (с Вашим номером телефона):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
private void button1_Click(object sender, EventArgs e)
{
   SMSC smsc = new SMSC(); // Создает экземпляр класса для работы с сервисом
   string[] r = smsc.send_sms("79999999999", "Проверочное SMS"); // Отправляет SMS на номер
 
   string Result = "";
   if(r.Length > 2) // Если ошибки нет
   {
      Result += "id = " + r[0] + Environment.NewLine
               + "количество sms = " + r[1] + Environment.NewLine
               + "стоимость = " + r[2] + Environment.NewLine
               + "баланс = " + r[3] + Environment.NewLine;
   }
   else // Если ошибка есть
   {
      Result += "id = " + r[0] + Environment.NewLine
               + "код ошибки = " + r[1] + Environment.NewLine;
   }
 
   // Выводит результат
   MessageBox.Show(Result);
}

ОТПРАВКА E-MAIL

Для того, чтобы отправить письмо на эл.почту (в т.ч. с прикрепленным файлом) из QLua скачайте архив EmailSender.zip, в нем находятся 2 файла: SenderEmail.dll - библиотека (для Quik 8 x64 используйте эту dll), которая подключается к скрипту QLua и Email.exe - приложение (почтовый клиент), написанное на C#, которое автоматически запускается и завершается и видно только в виде иконки (логотип сайта) в области уведомлений (правый нижний угол рабочего стола Windows). Оба этих файла нужно извлечь из архива и поместить в корневой каталог терминала QUIK (где info.exe).

Пример отправки EMAIL на ящик MAIL.RU из QLua
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
require("SenderEmail"); -- Подключает SenderEmail.dll
 
Run = true; -- Флаг поддержания работы скрипта
 
-- Основная функция скрипта, пока выполняется она, работает скрипт
function main()
   -- Отправляет письмо
   SenderEmail.SendEmail(
      "smtp.mail.ru", -- SMTP сервер
      "test@mail.ru", -- Ваш логин
      "MyPassword",   -- Ваш пароль
      "test@mail.ru", -- Email получателя
      "test@mail.ru", -- Email отправителя
      "Тема",         -- Тема письма
      "Текст письма", -- Текст письма
      "Тест.txt"      -- Путь к файлу вложения относительно Email.exe, либо полный путь
         -- (если не нужно, то оставить пустым (""), либо вообще убрать)
   );
   -- !!! Не отправляйте новое письмо, пока не дождетесь результата отправки предыдущего в функции EmailResult()
   while Run do sleep(10); end; -- Поддерживает работу функции main()
end;
 
-- Функция обратного вызова, вызывается автоматически после отправки письма
function EmailResult(res)
   -- Если отправка прошла успешно в res будет "OK", при ошибке "Ошибка отправки email: Текст ошибки"
   message(res);
end;
 
-- Функция вызывается при остановке скрипта
function OnStop()
   Run = false; -- Сбрасывает флаг, чтобы завершить цикл while в функции main()
end;

Если у Вас при использовании данного варианта отправки появятся ошибки, или Вы захотите внести какие-то коррективы в код, то можете скачать готовое решение для Visual Studio 2015 и перестроить (скомпилировать) его на своем компьютере.

Код DLL
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
//SenderEmail.cpp 2015(c)QuikLuaCSharp.ru
 
#include <windows.h>    // Подключает основной функционал для работы с ОС Windows
#include <thread>       // Подключает функционал для работы с потоками
#include <tlhelp32.h>   // Подключает функционал для получения информации о запущенных процессах
 
 
//=== Необходимые для Lua константы ============================================================================//
#define LUA_LIB
#define LUA_BUILD_AS_DLL
 
//=== Заголовочные файлы LUA ===================================================================================//
extern "C" {
#include "Lua\lauxlib.h"
#include "Lua\lua.h"
}
 
//=== Получает указатели на выделенную именованную память =====================================================//
// Имя для выделенной памяти для отправки Email
TCHAR EmailMemory[] = TEXT("EmailMemory");
// Создаст, или подключится к уже созданной памяти с таким именем
HANDLE hFileMapEmail = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, EmailMemory);
 
//КОНСТАНТЫ СОСТОЯНИЯ ПАМЯТИ
const char *QR = "_QR_"; // Память ожидает чтения Qlua (Qlua Read)
const char *QW = "_QW_"; // Память ожидает записи Qlua (Qlua Write)
const char *CR = "_CR_"; // Память ожидает чтения C# (C# Read)
const char *CW = "_CW_"; // Память ожидает записи C# (C# Write)
 
volatile PBYTE pb = NULL; // Указатель на байты данных памяти
 
TCHAR szPath[] = TEXT("Email.exe"); // Путь почтового клиента
STARTUPINFO si; // Необходимые для запуска процесса структуры
PROCESS_INFORMATION pi; //
 
bool SMTPclientWasRunning = false; // Флаг, что почтовый клиент уже был запущен ранее, чтобы не запустить еще одну копию
 
// Функция проверяет запущен ли процесс (программа) по его имени
bool IsProcessRun(const char * const processName)
{
   HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
 
   PROCESSENTRY32 pe;
   pe.dwSize = sizeof(PROCESSENTRY32);
   Process32First(hSnapshot, &pe);
 
   while (1) {
      if (strcmp(pe.szExeFile, processName) == 0) return true;
      if (!Process32Next(hSnapshot, &pe)) return false;
   }
}
 
//=== Стандартная точка входа для DLL ==========================================================================//
BOOL APIENTRY DllMain(HANDLE hModule, DWORD  fdwReason, LPVOID lpReserved)
{
   //Каждому событию соответствует свое значение аргумента fdwReason, передаваемого функции DllMain при его возникновении
   switch (fdwReason)
   {
      case DLL_PROCESS_ATTACH:  // Подключение DLL
         // Если почтовый клиент еще не запущен
         if (!IsProcessRun("Email.exe"))
         {
            //Запускает почтовый клиент
            memset(&si, 0, sizeof(si));
            si.cb = sizeof(si);
            memset(&pi, 0, sizeof(pi));
            CreateProcess(NULL, szPath, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
         }
         else
         {
            SMTPclientWasRunning = true; // Запоминает, что почтовый клиент уже был запущен (до подключения данной DLL)
         }
         return TRUE;
      case DLL_PROCESS_DETACH: // Отключение DLL
         // Если почтовый клиент был запущен данной DLL
         if (!SMTPclientWasRunning)
         {
            //Закрывает почтовый клиент
            TerminateProcess(pi.hProcess, 0);
            CloseHandle(pi.hProcess);
            CloseHandle(pi.hThread);
         }
         break;
      case DLL_THREAD_ATTACH: // Создание нового потока
         break;
      case DLL_THREAD_DETACH: // Завершение потока
         break;
   }
 
   return TRUE;
}
 
//=== Вспомогательные функции ==================================================================================//
 
//Функции проверки состояний памяти
static bool QluaReadReady() // Память ожидает чтения Qlua (Qlua Read)
{
   if (pb[0] == '_' && pb[1] == 'Q' && pb[2] == 'R' && pb[3] == '_') return true;
   return false;
}
static bool QluaWriteReady() // Память ожидает записи Qlua (Qlua Write)
{
   if (pb[0] == '_' && pb[1] == 'Q' && pb[2] == 'W' && pb[3] == '_') return true;
   return false;
}
 
//Функция читает память "EmailMemory" с периодичностью в 10 миллисекунд, пока не получит результат отправки email от C#,
//затем передает результат в QLua функцию EmailResult(), если она есть в скрипте
static int WaitingEmailResult(lua_State *L)
{
   lua_getglobal(L, "EmailResult"); //Находит в стеке Lua функцию по ее названию и помещает ее наверх стека
   if (lua_isfunction(L, -1)) // Если на верху стека функция
   {
      int callbackRef = luaL_ref(L, LUA_REGISTRYINDEX); //Получает индекс функции в специальной внутренней таблице (реестре) Lua
      // Ждет, пока C# запишет в память результат отправки email (память будет ожидать чтения Qlua)
      while (!QluaReadReady()) { Sleep(10); } // Пауза в 10 миллисекунд
      lua_rawgeti(L, LUA_REGISTRYINDEX, callbackRef); // Достает функцию из реестра Lua по ранее полученному индексу и помещает в стек
      if (lua_isfunction(L, -1)) // Если на верху стека функция
      {
         lua_pushstring(L, (char*)(pb + 4)); //Записывает в Lua-стек полученный результат (без управляющей константы)
         lua_call(L, 1, 1); //Вызывает выбранную функцию в скрипте QLua, передавая в нее 1 параметр (L - стек, 1 - количество передаваемых параметров, 1 - количество возвращаемых значений(нужно, чтобы обновлять стек))
      }
      //Очищает память
      for (int i = 0; i < 4096; i++)pb[i] = '\0';
      // Устанавливает константу "_QW_", сообщая тем самым, что память ожидает записи QLua
      memcpy(pb, QW, 4);
   }
   //Закрывает представление
   UnmapViewOfFile(pb);
 
   return (0); //Выход из функции
}
 
//=== Реализация функций, вызываемых из LUA ====================================================================//
 
// Получает строку Email информации и отправляет ее в C#
static int forLua_SendEmail(lua_State *L)
{
   //Если указатель на память получен
   if (hFileMapEmail)
   {
      // Получает доступ (представление) непосредственно к чтению/записи байт
      pb = (PBYTE)(MapViewOfFile(hFileMapEmail, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 4096));
      // Если доступ получен
      if (pb != NULL)
      {
         lua_getglobal(L, "EmailResult"); //Находит в стеке Lua функцию по ее названию и помещает ее наверх стека
         int callbackRef = luaL_ref(L, LUA_REGISTRYINDEX); //Получает индекс функции в специальной внутренней таблице (реестре) Lua
 
         //Очищает память
         for (int i = 0; i < 4096; i++)pb[i] = '\0';
         //Сообщает приложению C# о готовности отправить письмо
         memcpy(pb, "Q_READY", 7);
         //Ждет ответа от C# не более 3-х секунд
         // Получает время в миллисекундах, прошедших с запуска ОС
         unsigned long long TickCount = GetTickCount();
         while (true)
         {
            //Проверяет ответ о готовности от C# (ответом является "_QW_")
            if (QluaWriteReady())
            {
               break;//Выходит из цикла для отправки письма
            }
            else
            {
               //Проверяет задержку
               if (GetTickCount() - TickCount >= 3000)
               {
                  //Очищает память
                  for (int i = 0; i < 4096; i++)pb[i] = '\0';
                  //Сообщает о невозможности отправки
                  lua_rawgeti(L, LUA_REGISTRYINDEX, callbackRef); // Достает функцию из реестра Lua по ранее полученному индексу и помещает в стек
                  lua_pushstring(L, "ОШИБКА: Почтовый клиент не запущен !!!"); //Записывает в Lua-стек полученный результат
                  lua_call(L, 1, 0); //Вызывает выбранную функцию в скрипте QLua, передавая в нее 1 параметр (L - стек, 1 - количество передаваемых параметров, 0 - количество возвращаемых значений))
 
                  return (0);//Выходит из функции
               }
            }
 
            Sleep(1); // Пауза 1 миллисекунда
         }
         // Считывает из Lua-стека параметры Email-информации и объединяет их в одну строку
         char EmailInfo[4096] = "EMAIL_INFO;";
         strcat(EmailInfo, lua_tostring(L, 1)); //SMTP сервер
         strcat(EmailInfo, ";");
         strcat(EmailInfo, lua_tostring(L, 2)); //Ваш логин
         strcat(EmailInfo, ";");
         strcat(EmailInfo, lua_tostring(L, 3)); //Ваш пароль
         strcat(EmailInfo, ";");
         strcat(EmailInfo, lua_tostring(L, 4)); //Email получателя
         strcat(EmailInfo, ";");
         strcat(EmailInfo, lua_tostring(L, 5)); //Email отправителя
         strcat(EmailInfo, ";");
         strcat(EmailInfo, lua_tostring(L, 6)); //Тема письма
         strcat(EmailInfo, ";");
         strcat(EmailInfo, lua_tostring(L, 7)); //Текст письма
         if (lua_isstring(L, 8) && lua_tostring(L, 8) != "") // Если есть вложение (путь к файлу)
         {
            strcat(EmailInfo, ";");
            strcat(EmailInfo, lua_tostring(L, 8)); //Путь к файлу вложения
         }
 
         int Size = 0;
         // Считает количество символов в строке
         for (int i = 0; i < 4096; i++)
         {
            if (EmailInfo[i] == 0)break;
            Size++;
         }
         memcpy(pb + 4, EmailInfo, Size);// Записывает строку в память, начиная со 5-го байта
         memcpy(pb, CR, 4);// Устанавливает константу "_CR_", сообщая тем самым, что память записана и ожидает чтения C#
 
         std::thread thr(WaitingEmailResult, L); //Запускает выполнение функции в отдельном потоке
         thr.detach(); //Отсоединяет созданный поток от основного, делая его "фоновым"
      }
   }
   return(0);
}
 
//=== Регистрация реализованных в dll функций, чтобы они стали "видимы" для Lua ================================//
static struct luaL_reg ls_lib[] = {
   { "SendEmail", forLua_SendEmail },
   { NULL, NULL }
};
 
//=== Регистрация названия библиотеки, видимого в скрипте Lua ==================================================//
extern "C" LUALIB_API int luaopen_SenderEmail(lua_State *L) {
   luaL_openlib(L, "SenderEmail", ls_lib, 0);
   return 0;
}
Код C#
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
//Почтовый клиент 2015(c)QuikLuaCSharp.ru
using System;
using System.ComponentModel;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Net;
using System.Net.Mail;
using System.Threading;
using System.Windows.Forms;
 
namespace Email
{
   public partial class Form1 : Form
   {
      public static SmtpClient Client;
 
      // Выделенная именованная память
      public static MemoryMappedFile EmailMemory;
      // Объекты для чтения из памяти
      public static StreamReader SR_EmailMemory;
      // Объекты для записи в память
      public static StreamWriter SW_EmailMemory;
 
      //КОНСТАНТЫ СОСТОЯНИЯ ПАМЯТИ
      const string QR = "_QR_"; // Память ожидает чтения Qlua (Qlua Read)
      const string QW = "_QW_"; // Память ожидает записи Qlua (Qlua Write)
      const string CR = "_CR_"; // Память ожидает чтения C# (C# Read)
      const string CW = "_CW_"; // Память ожидает записи C# (C# Write)
 
      public static bool EmailRun = true; // Флаг работы приложения
 
      public static bool EmailSending = false; // Флаг, что идет отправка email
 
      public Form1()
      {
         InitializeComponent();
 
         // Создаст, или подключится к уже созданной памяти с таким именем
         EmailMemory = MemoryMappedFile.CreateOrOpen("EmailMemory", 4096, MemoryMappedFileAccess.ReadWrite);
         // Создает потоки для чтения
         SR_EmailMemory = new StreamReader(EmailMemory.CreateViewStream(), System.Text.Encoding.Default);
         // Создает потоки для записи
         SW_EmailMemory = new StreamWriter(EmailMemory.CreateViewStream(), System.Text.Encoding.Default);
         // Запускает функцию, которая в отдельном потоке ждет команды от QLua на отправку email
         GettingEmailInfo();
      }
 
      //Считывает информацию из памяти "EmailMemory"
      public string GetEmailInfo()
      {
         string EmailInfo = "";
 
         //Ждет от DLL сообщения о готовности отправить email ("Q_READY")
         while(EmailRun)
         {
            // Встает в начало потока
            SR_EmailMemory.BaseStream.Seek(0, SeekOrigin.Begin);
            // Считывает все, что есть в памяти, обрезая нули и др. сервисные символы
            EmailInfo = SR_EmailMemory.ReadToEnd().Trim('\0', '\r', '\n');
            // Если пришло сообщение о готовности, выходит из цикла для дальнейших действий
            if (EmailInfo == "Q_READY") break;
 
            Thread.Sleep(10); // Пауза в 10 миллисекунд, чтобы не перегружать процессор
         }
         if (!EmailRun) return ""; // Если приложение завершается, выходит из функции, чтобы не задерживать процесс
 
         // Встает в начало потока
         SW_EmailMemory.BaseStream.Seek(0, SeekOrigin.Begin);
         // Очищает память, заполняя "нулевыми байтами"
         for (int i = 0; i < 4096; i++) SW_EmailMemory.Write("\0");
         // Очищает все буферы и вызывает запись всех данных буферов в основной поток
         SW_EmailMemory.Flush();
         // Встает в начало потока
         SW_EmailMemory.BaseStream.Seek(0, SeekOrigin.Begin);
         // Записывает в начало константу "_QW_", означающую, что память ожидает записи QLua
         SW_EmailMemory.Write(QW);
         // Очищает все буферы и вызывает запись всех данных буферов в основной поток
         SW_EmailMemory.Flush();
 
         // Выполняет цикл, пока память не готова для чтения C#
         while (EmailInfo.Length == 0 || EmailInfo.Length < 4 || (EmailInfo.Length >= 4 && EmailInfo.Substring(0, 4) != CR))
         {
            // Встает в начало потока
            SR_EmailMemory.BaseStream.Seek(0, SeekOrigin.Begin);
            // Считывает все, что есть в памяти, обрезая нули и др. сервисные символы
            EmailInfo = SR_EmailMemory.ReadToEnd().Trim('\0', '\r', '\n');
 
            Thread.Sleep(10); // Пауза в 10 миллисекунд, чтобы не перегружать процессор
            if (!EmailRun) return ""; // Если приложение завершается, выходит из функции, чтобы не задерживать процесс
         }
         if (!EmailRun) return ""; // Если приложение завершается, выходит из функции, чтобы не задерживать процесс
 
         // Встает в начало потока
         SW_EmailMemory.BaseStream.Seek(0, SeekOrigin.Begin);
         // Очищает память, заполняя "нулевыми байтами"
         for (int i = 0; i < 4096; i++) SW_EmailMemory.Write("\0");
         // Очищает все буферы и вызывает запись всех данных буферов в основной поток
         SW_EmailMemory.Flush();
         // Встает в начало потока
         SW_EmailMemory.BaseStream.Seek(0, SeekOrigin.Begin);
         // Записывает в начало константу "_CW_", означающую, что память ожидает записи C#
         SW_EmailMemory.Write(CW);
         // Очищает все буферы и вызывает запись всех данных буферов в основной поток
         SW_EmailMemory.Flush();
 
         // Возвращает то, что прочитано, без управляющей константы
         return EmailInfo.Substring(4);
      }
 
      // Функция постоянно читает данные из памяти "EmailMemory" при помощи функции GetEmailInfo
      public void GettingEmailInfo()
      {
         //Запускает функцию получения сервисной информации в отдельном потоке, чтобы приложение откликалось на действия пользователя
         //Чтобы остановить выполнение данного потока, нужно переменной "EmailRun" присвоить значение "false"
         new Thread(() => // Создает новый поток
         {
            string EmailInfo = "";
            string[] EmailInfoParts;
 
            //Постоянный цикл в отдельном потоке
            while (EmailRun)
            {
               if (EmailSending) {Thread.Sleep(1); continue; } // Если в данный момент выполняется отправка email-сообщения, то ждет завершения
 
               //Получает сервисную информацию из памяти, если ее нет, то ждет
               EmailInfo = GetEmailInfo();
 
               // Разделяет полученную строку на элементы
               EmailInfoParts = EmailInfo.Split(';');
 
               if (EmailInfoParts.Length > 1 && EmailInfoParts[0] == "EMAIL_INFO")// Если получены данные для отправки письма
               {
                  //Отправляет письмо
                  Send(EmailInfoParts);
               }
 
               //Чтобы процесс не "забивал" одно из ядер процессора на 100% нужна пауза в 10 миллисекунд
               Thread.Sleep(10);
            }
         }).Start(); // Запускает поток
      }
 
      // Отправляет email
      private void Send(string[] EmailInfoParts)
      {
         string Server = EmailInfoParts[1];     // Сервер
         string Login = EmailInfoParts[2];      // Логин
         string Password = EmailInfoParts[3];   // Пароль
         string To = EmailInfoParts[4];         // Кому
         string From = EmailInfoParts[5];       // От кого
         string Subject = EmailInfoParts[6];    // Тема
         string Body = EmailInfoParts[7];       // Текст письма
         string Attachment = (EmailInfoParts.Length == 9) ? EmailInfoParts[8] : ""; // Полный, или относительный путь к файлу вложения (если есть)
 
         EmailSending = true; // Устанавливает флаг, что началась отправка email, чтобы не инициировать новую
 
         try // Пытается выполнить блок кода
         {
            Client = new SmtpClient(Server);                      // Инициализирует новый экземпляр класса SmtpClient, который отправляет электронную почту с помощью указанного сервера SMTP
            MailAddress from = new MailAddress(From);             // От кого
            MailAddress to = new MailAddress(To);                 // Кому
            MailMessage message = new MailMessage(from, to);      // Содает объект сообщения
            message.Body = Body;                                  // Добавляет к сообщению текст
            message.BodyEncoding = System.Text.Encoding.UTF8;     // Устанавливает кодировку для текста сообщения
            message.Subject = Subject;                            // Добавляет к сообщению тему
            message.SubjectEncoding = System.Text.Encoding.UTF8;  // Устанавливает кодировку для темы сообщения
 
            if (Attachment != "") // Если есть вложение (файл)
            {
               Attachment data = new Attachment(Attachment);      // Создает объект вложения
               message.Attachments.Add(data);                     // Добавляет вложение к сообщению
            }
 
            // Инициализирует новый экземпляр класса NetworkCredential с заданными значениями пароля и имени пользователя
            Client.Credentials = new NetworkCredential(Login, Password);
            // Указывает, использует ли SmtpClient протокол SSL для шифрования подключения
            Client.EnableSsl = true;
            // Происходит после завершения асинхронной операции по отправке электронной почты (регистрирует функцию обратного вызова)
            Client.SendCompleted += new SendCompletedEventHandler(SendCompletedCallback);
            // Отправляет указанное сообщение SMTP-серверу для доставки в качестве асинхронной операции
            Client.SendAsync(message, null);
         }
         catch (Exception ex) // Если при выполнении блока кода после try произошла ошибка
         {
            SetMemoryResult("Ошибка отправки email: " + ex.ToString()); // Записывает в память результат отправки email
            EmailSending = false; // Сбрасывает флаг (процесс отправки завершен)
            // Отправляет сообщение QUIT на SMTP-сервер, правильно завершает TCP-подключение и освобождает все ресурсы, используемые текущим экземпляром класса SmtpClient
            Client.Dispose();
         }
      }
 
      //Функция записывает в память результат отправки email
      private static void SetMemoryResult(string Result)
      {
         string S = "";
         // Ожидает в цикле разрешения на запись в память
         while (EmailRun)
         {
            // Встает в начало потока
            SR_EmailMemory.BaseStream.Seek(0, SeekOrigin.Begin);
            // Считывает все, что есть в памяти
            S = SR_EmailMemory.ReadToEnd();
            // Если память ожидает записи C#, выходит из цикла while, иначе ждет 10 миллисекунд
            if (S.Length > 0 && S.Substring(0, 4) == CW) break; else Thread.Sleep(10);
         }
 
         // Встает в начало потока
         SW_EmailMemory.BaseStream.Seek(0, SeekOrigin.Begin);
         // Очищает память, заполняя "нулевыми байтами"
         for (int i = 0; i < 4096; i++) SW_EmailMemory.Write("\0");
         // Очищает все буферы и вызывает запись всех данных буферов в основной поток
         SW_EmailMemory.Flush();
         // Встает в начало потока
         SW_EmailMemory.BaseStream.Seek(0, SeekOrigin.Begin);
         // Записывает в начало константу "_QR_", означающую, что память ожидает чтения QLua и далее записывает саму команду
         SW_EmailMemory.Write(QR + Result);
         // Очищает все буферы и вызывает запись всех данных буферов в основной поток
         SW_EmailMemory.Flush();
      }
 
      // Функция вызывается по окончанию асинхронной отправки почтового сообщения
      private static void SendCompletedCallback(object sender, AsyncCompletedEventArgs e)
      {
         if (e.Error != null) // Если произошла ошибка
         {
            SetMemoryResult("Ошибка отправки email: " + e.Error.ToString());  // Записывает в память результат отправки email
            EmailSending = false; // Сбрасывает флаг (процесс отправки завершен)
            // Отправляет сообщение QUIT на SMTP-сервер, правильно завершает TCP-подключение и освобождает все ресурсы, используемые текущим экземпляром   класса SmtpClient
            Client.Dispose();
         }
         else // Отправка прошла без ошибок
         {
            SetMemoryResult("OK");  // Записывает в память результат отправки email
            EmailSending = false; // Сбрасывает флаг (процесс отправки завершен)
            // Отправляет сообщение QUIT на SMTP-сервер, правильно завершает TCP-подключение и освобождает все ресурсы, используемые текущим экземпляром   класса SmtpClient
            Client.Dispose();
         }
      }
 
      // Функция вызывается при закрытии данного приложения
      private void Form1_FormClosing(object sender, FormClosingEventArgs e)
      {
         notifyIcon1.Visible = false;  // Не отображать иконку
         EmailRun = false;             // Сбрасывает флаг работы приложения, чтобы завершился отдельный поток
      }
 
      // Функция вызывается при изменении размеров формы, следовательно, и при сворачивании и разворачивании
      private void Form1_Resize(object sender, EventArgs e)
      {
         if (WindowState == FormWindowState.Minimized) // Если форма свернута
         {
            Hide();                       // Скрывает форму
            notifyIcon1.Visible = true;   // Отображает иконку в области уведомлений
         }
      }
 
      // Функция вызывается при клике в контекстном меню, которое появляется при клике правой кнопкой мыши по иконке
      private void contextMenuStrip1_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
      {
         if (e.ClickedItem.Text == "Закрыть") // Если клик по пункту "Закрыть"
         {
            Application.Exit();  // Закрывает приложение
            EmailRun = false;    // Сбрасывает флаг работы приложения, чтобы завершился отдельный поток
         }
      }
   }
}

Если по какой-то причине Вы не можете, или не хотите, использовать Visual Studio 2015, то можете скачать готовое решение для Visual Studio 2010. Данное решение использует библиотеку "BOOST" для C/C++, если Вы не знаете как использовать данную библиотеку, можете ознакомиться здесь.

Еще один пример отправки EMAIL на ящик MAIL.RU из C#
На форму добавьте кнопку, сделайте по ней двойной щелчок мышкой и в созданную функцию добавьте следующий код (с Вашими данными почтового ящика), а так же, функцию обратного вызова для получения результата асинхронной отправки письма:

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
private void button1_Click(object sender, EventArgs e)
{
   string Server = "smtp.mail.ru";
   int Port = 25;
   string Login = "test@mail.ru";
   string Password = "MyPassword";
   string To = "test@mail.ru"; // Кому
   string From = "test@mail.ru"; // От кого
   string Subject = "Тест SMTP C#"; // Тема
   string Body = "Тестовое сообщение"; // Текст письма
   // Инициализирует новый экземпляр класса SmtpClient, который отправляет электронную почту с помощью указанного сервера SMTP и порта
   SmtpClient Client = new SmtpClient(Server, Port);
   // Инициализирует новый экземпляр класса NetworkCredential с заданными значениями пароля и имени пользователя
   Client.Credentials = new NetworkCredential(Login, Password);
   // Указывает, использует ли SmtpClient протокол SSL для шифрования подключения
   Client.EnableSsl = true;
   // Происходит после завершения асинхронной операции по отправке электронной почты (регистрирует функцию обратного вызова)
   Client.SendCompleted += new SendCompletedEventHandler(SendCompletedCallback);
   // Отправляет указанное сообщение SMTP-серверу для доставки в качестве асинхронной операции.
   //Отправитель, получатели, тема и основная часть сообщения указываются с помощью объектов String
   Client.SendMailAsync(From, To, Subject, Body);
   // Отправляет сообщение QUIT на SMTP-сервер, правильно завершает TCP-подключение и освобождает все ресурсы, используемые текущим экземпляром   класса SmtpClient
   Client.Dispose();
}
 
// Функция вызывается по окончанию асинхронной отправки почтового сообщения
private static void SendCompletedCallback(object sender, AsyncCompletedEventArgs e)
{
   if (e.Error != null)
   {
      MessageBox.Show("Ошибка отправки email: " + e.Error.ToString());
   }
   else
   {
      MessageBox.Show("Сообщение email успешно отправлено!");
   }
}

Некоторые почтовые сервисы предоставляют оповещение по SMS о новых письмах, по этому, этот способ можно использовать как альтернативное оповещение.

Если у Вас появились какие-то вопросы, задайте их в комментариях под статьей !!!