15 мая 2023 года "Исходники.РУ" отмечают своё 23-летие!
Поздравляем всех причастных и неравнодушных с этим событием!
И огромное спасибо всем, кто был и остаётся с нами все эти годы!

Главная Форум Журнал Wiki DRKB Discuz!ML Помощь проекту

 

Класс для протокола SMTP

Автор: Asif Rasheed.

SMTP (Simple Mail Transfer Protocol) используется для отправки почты по назначению. Полное описание протокола SMTP содержится в RCF 821. Данный класс можно использовать в различных приложениях, которые отправляют почту через протокол SMTP.

В классе содержится несколько методов. Для удобства программирования методы названы по аналогии с командами протокола SMTP. В этом классе используется CSocket как член класса, с той целью, чтобы можно было работать с потоками.

Вот собственно код класса.

//////////////////////////////////////////////////////////////////////
// SMTP.h: файл заголовка CSMTP класса.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_SMTP_H__617F7E82_7F4D_11D1_88A0_00001C302581__INCLUDED_)
#define AFX_SMTP_H__617F7E82_7F4D_11D1_88A0_00001C302581__INCLUDED_

#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000

#define CONNECTION_CHECK 0
#define HELLO_CHECK 1
#define MAIL_CHECK 2
#define RCPT_CHECK 3
#define DATA_START_CHECK 4
#define DATA_END_CHECK 5
#define QUIT_CHECK 6
#define DATA_CHECK 7


class CSMTP 
{
public:
	BOOL Mail(); // 
	CString GetErrorMessage();
	BOOL Data(CString Subject, CString Body);
	CString GetTo();
	BOOL SetTo(CString to);
	CString GetFrom();
	void SetFrom(CString from);
	BOOL Mail(CString from);
	BOOL Disconnect();
	CString GetHost();
	void SetHost(CString Host);
	BOOL Connect(CString Host, CString Me);
	BOOL Connect();
	CSMTP();
	virtual ~CSMTP();
	
private:
	CString GetError(CString Response);
	CString m_ErrorMessage;
	BOOL CheckResponse(int Type);
	int m_NoOfTo;
	CStringArray m_To;
	CString m_From;
	CSocket m_SMTPServer;
	CString m_Host;
   };

#endif // !defined(AFX_SMTP_H__617F7E82_7F4D_11D1_88A0_00001C302581__INCLUDED_)


//////////////////////////////////////////////////////////////////////////
// SMTP.cpp: методы класса CSMTP.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "SMTP.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Конструктор/Деструктор
//////////////////////////////////////////////////////////////////////

CSMTP::CSMTP()
{
	m_NoOfTo = 0;
	m_SMTPServer.Create();
}

CSMTP::~CSMTP()
{
	m_SMTPServer.Close();
}

// Коннектимся к SMTP Серверу
BOOL CSMTP::Connect()
{
	return Connect(m_Host,m_From);
}

// Коннектимся к SMTP Серверу
BOOL CSMTP::Connect(CString Host,CString From)
{
	if (!m_SMTPServer.Connect(Host,25)) // 25 - это SMTP порт
	{
		m_ErrorMessage = _T("Server cannot be connected");
		return FALSE;
	}
	else
	{
		if(CheckResponse(CONNECTION_CHECK)==FALSE)
			return FALSE;
		
		char buf [512];
		
		wsprintf (buf, "HELO %s\r\n", (LPCSTR) From);
		m_SMTPServer.Send(buf, strlen (buf)); 
		if (CheckResponse(HELLO_CHECK)==FALSE)
			return FALSE;
		else 
			return TRUE; 
		
		return TRUE;
	}
}

// Устанавливает адрес хоста
void CSMTP::SetHost(CString Host)
{
	m_Host = Host;
}

// Возвращаем адрес хоста
CString CSMTP::GetHost()
{
	return m_Host;
}

// Посылаем SMTP серверу команду "QUIT"
BOOL CSMTP::Disconnect()
{
	char buf[256];
	
	wsprintf (buf, "QUIT \r\n");
	m_SMTPServer.Send(buf, strlen (buf)); 
	if (CheckResponse(QUIT_CHECK)==FALSE)
		return FALSE;
	else 
		return TRUE;
}

// Посылаем SMTP серверу команду "MAIL"
BOOL CSMTP::Mail(CString from)
{
	char buf[256];
	
	wsprintf (buf, "MAIL From:<%s>\r\n", (LPCSTR) from);
	m_SMTPServer.Send(buf, strlen (buf)); 
	if (CheckResponse(MAIL_CHECK)==FALSE)
		return FALSE;
	else 
		return TRUE; 
}

// Устанавливаем строку From
void CSMTP::SetFrom(CString from)
{
	m_From = from;
}

// Возвращаем строку From
CString CSMTP::GetFrom()
{
	return m_From;
}

// Устанавливаем строку TO
BOOL CSMTP::SetTo(CString to)
{
	char buf[256];
	m_To.Add(to); // Сохраняем содержимое "to"
	
	wsprintf (buf, "RCPT TO:<%s>\r\n", (LPCSTR) to);
	m_SMTPServer.Send(buf, strlen (buf)); 
	if (CheckResponse(RCPT_CHECK)==FALSE)
		return FALSE;
	else 
		return TRUE; 
	
}

// Возвращаем строку TO
CString CSMTP::GetTo()
{ 
	if(m_To.GetSize()>=m_NoOfTo)
	{
		m_NoOfTo++;
		return m_To[m_NoOfTo-1];
	}
	else
		return _T("No more To available");
}

// Посылаем SMTP серверу команду "DATA"
BOOL CSMTP::Data(CString Subject, CString Body)
{
	char buf[256];
	
	wsprintf (buf, "DATA\r\n");
	
	m_SMTPServer.Send(buf, strlen (buf)); 
	if (CheckResponse(DATA_CHECK)==FALSE)
		return FALSE;
	else 
	{
		wsprintf (buf, "SUBJECT:%s\r\n", (LPCSTR) Subject);
		m_SMTPServer.Send(buf, strlen (buf)); 
		
		wsprintf (buf, "%s\r\n", (LPCSTR) Body);
		m_SMTPServer.Send(buf, strlen (buf)); 
		
		wsprintf (buf, ".\r\n");
		m_SMTPServer.Send(buf, strlen (buf)); 
		
		return TRUE;
	}
}

// Этот метод проверяет ответы от сервера
BOOL CSMTP::CheckResponse(int Type)
{
	char buf [1000];
	char temp[3];
	
	for (int i=0;i < 512;i++)
		buf[i]='\0';
	
	// Получаем данные от сервера
	m_SMTPServer.Receive(buf, sizeof(buf));
	strncpy(temp,buf,3);
	int temp2 = atoi(temp);
	switch (Type)
	{
	case CONNECTION_CHECK:
		if (temp2 != 220)
		{
			m_ErrorMessage = GetError((LPCTSTR)buf);
			return FALSE;
		} 
		break;
		
	case HELLO_CHECK:
		if (temp2 != 250)
		{
			m_ErrorMessage = GetError((LPCTSTR)buf);
			return FALSE;
		} 
		break;
	case MAIL_CHECK:
		if (temp2 != 250)
		{
			m_ErrorMessage = GetError((LPCTSTR)buf);
			return FALSE;
		} 
		break;
	case RCPT_CHECK:
		if (temp2 != 250)
		{
			m_ErrorMessage = GetError((LPCTSTR)buf);
			return FALSE;
		} 
		break;
	case DATA_START_CHECK:
		if (temp2 != 354)
		{
			m_ErrorMessage = GetError((LPCTSTR)buf);
			return FALSE;
		} 
		break;
	case DATA_END_CHECK:
		if (temp2 != 250)
		{
			m_ErrorMessage = GetError((LPCTSTR)buf);
			return FALSE;
		} 
		break;
	case QUIT_CHECK:
		if (temp2 != 221)
		{
			m_ErrorMessage = GetError((LPCTSTR)buf);
			return FALSE;
		} 
		break;
	case DATA_CHECK:
		if (temp2 != 354)
		{
			m_ErrorMessage = GetError((LPCTSTR)buf);
			return FALSE;
		} 
		break;
		
	}
	return TRUE;
}

// Получаем сообщение об ошибке
CString CSMTP::GetErrorMessage()
{
	return m_ErrorMessage;
}

// Сопоставляем сообщению об ошибке - номер ошибки
CString CSMTP::GetError(CString Response)
{
	if(Response.Find("211"))
		return _T("System status or system help reply");
	if(Response.Find("214"))
		return _T("Help Message");
	if(Response.Find("220"))
		return _T("Service is ready");
	if(Response.Find("221"))
		return _T("Service closing transmission channel");
	if(Response.Find("250"))
		return _T("Requested mail action okay, completed");
	if(Response.Find("251"))
		return _T("user not local: will forward to forward path");
	if(Response.Find("354"))
		return _T("Start mail input; end with <CRLF>.<CRLF>");
	
	return _T("No Error Number is matched with ")+Response;
}

// Метод Mail без параметров
BOOL CSMTP::Mail()
{
	return Mail(m_From);
}

А теперь небольшой пример использования класса,

CSMTP m_smtp;
m_smtp.Connect("khi.compol.com","aasif@khi.compol.com");
m_smtp.Mail("aasif@khi.compol.com");
m_smtp.SetTo("zafir@home.com");
m_smtp.Data("test message","Это тестовое сообщение ... ");
m_smtp.Disconnect(); 

Не забудьте вкючить в заголовочный файл Вашего проекта #include <afxsock.h>