Цель работы.

Получение практических навыков разработки и программирования клиентских приложений и работы с протоколами электронной почты (SMTP и POP3)

Краткое описание.

Разработать клиентское приложение обеспечивающее работу с электронной почтой (Прием и отправку писем) с использованием Visual Studio.

Постановка задачи.

1)  разработать клиентское приложение обеспечивающее отправку электронной почты с помощью высокоуровневого программирования (использование уже готового класса Mail).

2)  Разработать клиентское приложение обеспечивающее отправку электронной почты с использованием низко уровневого программирования (создание и программирование сокетов для обеспечения передачи данных между клиентом и сервером)

3)  Разработать клиентское приложение способное загрузить письма с почтового ящика пользователя

Теоретическая часть.

Механизм обмена информацией между приложениями (TCP).

Для того, чтобы приложения могли общаться между собой, необходимо использовать, так называемые сокеты.

Со́кеты (англ. socket — углубление, гнездо, разъём) — название программного интерфейса для обеспечения обмена данными между процессами. Процессы при таком обмене могут исполняться как на одной ЭВМ, так и на различных ЭВМ, связанных между собой сетью. Сокет — абстрактный объект, представляющий конечную точку соединения.

Прежде чем начать передачу данных, необходимо создать сокет, и как то его обозвать, а так же необходимо установить его тип и определить по какому протаколу он будет работать (TCP или UDP). Дальше последовательность действий немного различается у клиентского и у серверного приложения.

НЕ нашли? Не то? Что вы ищете?

Серверное приложение.

В серверном приложении необходимо создать сокет, предназначенный для прослушивания канала связи. После чего необходимо назначить сокету порт который он будет слушать (например для веб-сервера обычно это 80 порт).

Созданный таким способом сокет, предназначен только для прослушивания, и для принятия входящего подключения. Однако следует обратить внимание, что через этот сокет данные никогда не идут. В момент соединения создается еще один сокет которому передается подключение. Следовательно после соединения, у серверного приложения уже имеется 2 сокета один из которых продолжает принимать входящие подключения а другой уже с установленным подключением с другим таким же сокетом, но на клиентском приложении. Именно этот сокет используется для передачи данных между серверным и клиентским приложением. Оба сокета работают через один и тот же порт. Соответственно когда приходит пакет с данными на какой то порт, то если он идет от нового клиента то он попадает на сокет предназначенный для принятия подключения. Если же пакет пришёл от приложения которое уже установило соединение, то он попадает на уже созданный при подключении сокет.

Клиентское приложение.

В клиентском приложении все гораздо проще. После создания сокета он делается не слушающим, а готовым к подключению. После чего, зная IP адрес и порт сервера, приложение подключает его к серверному приложению, где для этого сокета создается такой же и между ними образуется соединение используемое для передачи данных.

Протоколы электронной почты.

Протокол исходящей почты SMTP.

SMTP (англ. Simple Mail Transfer Protocol — простой протокол передачи почты) — это сетевой протокол, предназначенный для передачи электронной почты в сетях TCP/IP. SMTP используется для отправки почты от пользователей к серверам и между серверами для дальнейшей пересылки к получателю. 

Сервер SMTP — это конечный автомат с внутренним состоянием. Клиент передает на сервер строку команда<пробел>параметры<перевод строки>. Сервер отвечает на каждую команду строкой, содержащей код ответа и текстовое сообщение, отделенное пробелом. Код ответа — число от 100 до 999, представленное в виде строки, трактующийся следующим образом:

    2ХХ — команда успешно выполнена 3XX — ожидаются дополнительные данные от клиента 4ХХ — временная ошибка, клиент должен произвести следующую попытку через некоторое время 5ХХ — неустранимая ошибка

Пример простейшей SMTP-сессии

C: — клиент, S: — сервер

S: (ожидает соединения)

C: (Подключается к порту 25 сервера)

S:220 pany. tld ESMTP CommuniGate Pro 5.1.4i is glad to see you!

C:HELO

S:250 domain name should be qualified

C:MAIL FROM: <*****@***ru>

S:250 *****@***ru sender accepted

C:RCPT TO:<*****@***tld>

S:250 *****@***tld ok

C:RCPT TO: <*****@***tld>

S:550 *****@***tld unknown user account

C:DATA

S:354 Enter mail, end with "." on a line by itself

C:Hi!

C:.

S:message accepted for delivery

C:QUIT

S:221 pany. tld CommuniGate Pro SMTP closing connection

S: (закрывает соединение)

Проблемы безопасности SMTP

Изначально SMTP не поддерживал единой схемы авторизации. В результате этого спам стал практически неразрешимой проблемой, так как было невозможно определить, кто на самом деле является отправителем сообщения — фактически можно отправить письмо от имени любого человека. В настоящее время производятся попытки решить эту проблему при помощи спецификаций SPF, Sender ID. Единой спецификации на настоящий момент не существует.

Практическая часть.

Задание №1.

Так как отправка электронного письма является достаточно тривиальной задачей, то во многих высокоуровневых языках программирования уже не требуется создавать сокеты, инициализировать соединение и понимать принцип действия протокола SMTP. Достаточно использовать класс, который уже сам может это делать, все, что для этого надо, это создать экземпляр этого класса (объект), после чего сообщить ему необходимые параметры, (адрес сервера, имя пользователя, пароль, кому должно дойти наше письмо, ну и, разумеется, сам текст письма). После чего последний шаг - это дать этому объекту команду «отправить».

На первое задание вам предоставлено уже готовое окно приложения, которое уже имеет в себе текстовые поля, а так же кнопку «Отправить» (то есть все необходимые элементы интерфейса подобной программы).

Запустите visual studio, после чего открой те проект с уже готовой формой. Вы увидите такую форму.

Рис. 1: Внешний вид окна приложения.

Для того, чтобы редактировать код, который будет выполняться при нажатии кнопки «отправить» кликните по ней два раза левой кнопкой мыши, после чего откроется текстовое поле в котором вы увидите:

Код:

private void button1_Click(object sender, EventArgs e)

{

}

Все что, вы введете в фигурные скобки, будет выполнено сразу после нажатия нашей кнопки «отправить»

Теперь, для того, чтобы работать с нашим классом, нам необходимо подключить пространство имен в котором описан нужный нам класс. В самом начале текстового поля находится список всего подключенного.

Код:

using System;

using System. Collections. Generic;

using ponentModel;

using System. Data;

using System. Drawing;

using System. Linq;

using System. Text;

using System. Windows. Forms;

Добавьте в конец этого списка следующую строчку.

Код:

using . Mail;

Теперь вернемся в ту часть кода, где будут описаны действия, сопровождающиеся нажатием кнопки. И создадим объект, отправляющий почту.

Код:

SmtpClient smtp= new SmtpClient(textBoxServer. Text);

Эта строка создаст нам новый объект с именем smtp, который будет подключаться к серверу, адрес которого будет написан в текстовом поле textBoxServer. Соответственно, если нажать на кнопку «отправить» до того как будет введен адрес сервера, объект не сможет подключиться.

Теперь создадим еще два объекта: from и to, которые будут хранить в себе содержание текстовых полей textBoxLogin. Text и textBoxToMail. Text . Имя пользователя и почтовый ящик получателя соответственно.

Код:

MailAddress from = new MailAddress(textBoxLogin. Text);

MailAddress to = new MailAddress(textBoxToMail. Text);

Так же необходимо создать объект письмо (message), которое обязательно должно иметь адрес получателя (форма textBoxToMail) и адрес отправителя (форма textBoxLogin).

Код:

MailMessage message = new MailMessage(from, to);

Так как у нас объекты from и to содержат адреса отправителя и получателя, то необходимо указать их в качестве параметров. Собственно говоря, мы их именно для этого и создавали, иначе объект message не понял, что это именно адреса.

Осталось только прикрепить к письму текст сообщения и тему.

Код:

message. Subject = textBoxSubject. Text;

message. Body = richTextBoxBody. Text

Наше сообщение готово к отправке, осталось только назначить его нашему, уже созданному объекту smtp, который отправит его.

Для этого необходимо указать мя пользователя и пароль от которого мы будем отправлять.

Код:

smtp. Credentials = new . NetworkCredential(textBoxLogin. Text, textBoxPassword. Text);

Все готово. Остался последний шаг, дать команду «отправить письмо»

Код:

try

{

smtp. Send(message);

}

catch (Exception ex)

{

labelStatus. Text = "Отправка не удалась: " + ex. Message;

}

finally

{

labelStatus. Text = "Письмо отправлено";

}

На всякий случай, чтобы быть уверенными в том, что наше сообщение ушло, мы используем try. А уже в нем мы даем команду к отправке (smtp. Send(message);). Соответственно, если вдруг сообщение не удалось отправить, то в поле labelStatus появится информация об ошибке, в противном случае появится надпись "Письмо отправлено".

Теперь скомпилируйте вашу программу и испытайте ее.

Задание №2

Во второй части задания мы познакомимся с протоколом POP3. Этот протокол используется почтовым клиентом для получения сообщений электронной почты с сервера.

Для второго задания также имеется проект с готовым окном приложения, а также несколькими классами, предназначенными для работы с этим протоколом и с кодировкой. В них полностью реализована работа с протоколом POP3, написан простенький «парсер» MIME, (Multipurpose Internet Mail Extensions - стандарт, описывающий передачу различных типов данных по электронной почте, а также, шире, спецификация для кодирования информации и форматирования сообщений таким образом, чтобы их можно было пересылать по Интернету.) для того, чтобы наш клиент показывал тело сообщения. Еще создан класс по работе с кодировками koi8-r и QP Encoding (в них передается тело сообщения).

Рис. 2: Внешний вид окна приложения.

Запустите Visual Studio. Можете посмотреть реализацию вышеописанных вещей. Но пока почтовый клиент не работает. Откройте окно приложения, кликните 2 раза по кнопке «Получить список», вы увидите следующий код:

private void buttonGetList_Click(object sender, EventArgs e)

{

}

Для начала нам необходимо очистить список писем (на случай, если мы уже получали письма один раз), сделаем это следующим образом:

listBoxMailList. Items. Clear();

Теперь, используя знакомую нам конструкцию try/catch, будем получать письма с сервера:

try

{

// Создаем экземпляр класса POP3 для работы с почтой:

Pop3 obj = new Pop3();

// Создаем экземпляр класса encodings для работы с кодировками:

encodings enc = new encodings();

// Вызываем метод Connect, сообщаем ему содержимое текстовых полей с адресом, логином и паролем. Так происходит соединение с сервером:

obj. Connect(textBoxServer. Text, textBoxLogin. Text, textBoxPassword. Text);

// Получаем список писем:

ArrayList list = obj. List();

// В этом массиве будут хранится "тела" писем:

messages = new string[list. Count];

После этого обрабатываем каждое письмо следующим образом:

foreach (Pop3Message msg in list)

{

// Получаем само письмо с сервера:

Pop3Message msg2 = obj. Retrieve(msg);

// Преобразуем из кодировки Quoted-printable в KOI8-R, а затем в Unicode для правильного отображения русского языка:

msg2.message = enc. koi8r_to_unicode(enc. qp_encoding_to_koi8r(msg2.message));

// Добавляем номер и отправителя в наш список:

listBoxMailList. Items. Add(msg2.number. ToString() + ": " + obj. getMessageFrom(msg2));

// Обрабатываем (получаем из MIME) тело письма:

msg2=obj. getMessageBody(msg2);

// Записываем в массив тело письма:

messages[msg2.number - 1] = msg2.message;

}

Все, мы получили всю информацию от сервера, отключаемся:

obj. Disconnect();

}

Не забываем обрабатывать возможные ошибки:

catch (Pop3Exception ex)

{

System. Console. WriteLine(ex. ToString());

}

catch (System. Exception ex)

{

System. Console. WriteLine(ex. ToString());

}

}

Теперь нам необходимо все это отображать. Кликнем два раза по элементу ListBox. И добавляем следующее:

try

{

// Отображаем тело письма, выбранного из списка в текстовом поле на форме:

richTextBoxMailBody. Text = messages[listBoxMailList. SelectedIndex];

}

catch (System. Exception ex)

{

System. Console. WriteLine(ex. ToString());

}

Все. Теперь все готово. Нажмите F5 и протестируйте написанное приложение.