Hi,
Acabei de fazer uma classe que demonstra a implementação básica do protocolo SMTP (lado cliente).
Eu testei a classe no Windows e no Linux, com êxito em ambas as plataformas.
Bem, esta classe aborda os comandos básicos para enviar um email utilizando o protocolo SMTP, tais como, MAIL FROM, RCPT TO, DATA, etc; além da possibilidade de enviar emails com conteúdo HTML.
Postarei, respectivamente, o código da classe + dependências, um código de exemplo de uso e, por fim, um arquivo .ZIP contendo todos os arquivos.
smtp_class.h#include "base64.h"
#define SMTP_PORTA 25
#ifdef WIN32
class WinSock{
private:
WSADATA wsa;
int iniciado;
public:
void Iniciar();
void Terminar();
}WinSock;
#endif
class SMTP{
private:
#ifdef WIN32
WSADATA wsa;
#endif
int sock;
struct sockaddr_in addr;
struct hostent * host;
char buffer [1024];
string cmd;
string nome_de,email_assunto,email_msg;
void envia_comando(string * dados);
void recebe_resposta();
int verifica_codigo(string codigo);
int conectado;
public:
void Conectar(string servidor);
void Desconectar();
void Logar(string user,string password);
void De(string nome_remetente,string email_remetente);
void Para(string email_dest);
void Assunto(string assunto);
void Mensagem(string msg);
void Enviar();
};
/////////////////////////////////////////////////////////////////////////////////////////
#ifdef WIN32
void WinSock::Iniciar()
{
if(iniciado == 1)
throw "O Winsock ja foi inicializado!";
if(WSAStartup(0x202,&wsa) == -1)
throw "Erro ao incializar o Winsock.";
iniciado = 1;
}
/////////////////////////////////////////////////////////////////////////////////////////
void WinSock::Terminar()
{
if(WSACleanup() == -1)
throw "Falha ao finalizar o uso do WinSock.";
iniciado = 0;
}
/////////////////////////////////////////////////////////////////////////////////////////
#endif
void SMTP::Conectar(string servidor)
{
if(conectado == 1)
throw "Ja existe uma conexao estabelecida!";
if((sock = socket(AF_INET,SOCK_STREAM,0)) == -1)
throw "Erro ao criar um socket principal.";
if(!(host = gethostbyname(servidor.c_str())))
throw "Erro ao resolver o host do servidor especificado.";
addr.sin_family = AF_INET;
addr.sin_port = htons(SMTP_PORTA);
addr.sin_addr.s_addr = *(unsigned long*)host->h_addr;
memset(&addr.sin_zero,0x0,sizeof(addr.sin_zero));
if(connect(sock,(struct sockaddr*)&addr,sizeof(addr)) == -1)
throw "Erro ao se conectar no servidor!";
recebe_resposta();
if(!verifica_codigo("220"))
throw "O servidor retornou uma resposta inesperada!";
cmd = "EHLO localhost\r\n";
envia_comando(&cmd);
recebe_resposta();
if(!verifica_codigo("250"))
throw "O servidor retornou uma resposta inesperada!";
conectado = 1;
}
/////////////////////////////////////////////////////////////////////////////////////////
void SMTP::Desconectar()
{
#ifdef WIN32
closesocket(sock);
#else
close(sock);
#endif
conectado = 0;
}
/////////////////////////////////////////////////////////////////////////////////////////
void SMTP::Logar(string user,string password)
{
cmd = "auth login\r\n";
envia_comando(&cmd);
recebe_resposta();
if(!verifica_codigo("334"))
throw "O servidor retornou uma resposta inesperada!";
cmd = base64((unsigned char*)user.c_str(),user.length());
cmd += "\r\n";
envia_comando(&cmd);
recebe_resposta();
if(!verifica_codigo("334"))
throw "O servidor retornou uma resposta inesperada!";
cmd = base64((unsigned char*)password.c_str(),password.length());
cmd += "\r\n";
envia_comando(&cmd);
recebe_resposta();
if(!verifica_codigo("235"))
throw "Falha no login!";
}
/////////////////////////////////////////////////////////////////////////////////////////
void SMTP::De(string nome_remetente,string email_remetente)
{
cmd = "MAIL FROM: <" + email_remetente + ">\r\n";
envia_comando(&cmd);
recebe_resposta();
if(!verifica_codigo("250"))
throw "O email do remetente foi recusado!";
nome_de = nome_remetente;
}
/////////////////////////////////////////////////////////////////////////////////////////
void SMTP::Para(string email_dest)
{
cmd = "RCPT TO: <" + email_dest + ">\r\n";
envia_comando(&cmd);
recebe_resposta();
if(!verifica_codigo("250"))
throw "O email do destinatario foi recusado!";
}
/////////////////////////////////////////////////////////////////////////////////////////
void SMTP::Assunto(string assunto)
{
email_assunto = assunto;
}
/////////////////////////////////////////////////////////////////////////////////////////
void SMTP::Mensagem(string msg)
{
email_msg = msg;
}
/////////////////////////////////////////////////////////////////////////////////////////
void SMTP::Enviar()
{
cmd = "DATA\r\n";
envia_comando(&cmd);
recebe_resposta();
if(!verifica_codigo("354"))
throw "O servidor retornou uma resposta inesperada!";
cmd = "From: " + nome_de + "\r\n";
envia_comando(&cmd);
if(email_assunto.size() > 0){
cmd = "Subject: " + email_assunto + "\r\n";
envia_comando(&cmd);
email_assunto = "";
}
cmd = "MIME-Version: 1.0\r\n";
envia_comando(&cmd);
cmd = "Content-Type: text/html\r\n";
envia_comando(&cmd);
if(email_msg.size() > 0){
cmd = "\r\n" + email_msg + "\r\n";
envia_comando(&cmd);
email_msg = "";}
cmd = ".\r\n";
envia_comando(&cmd);
recebe_resposta();
if(!verifica_codigo("250"))
throw "Ocorreu um erro ao enviar o email!";
cmd = "QUIT\r\n";
envia_comando(&cmd);
}
/////////////////////////////////////////////////////////////////////////////////////////
void SMTP::envia_comando(string * dados)
{
if(send(sock,dados->c_str(),dados->length(),0) == -1)
throw "Erro ao enviar comandos ao servidor!";
}
/////////////////////////////////////////////////////////////////////////////////////////
void SMTP::recebe_resposta()
{
memset(buffer,0x0,sizeof(buffer));
if(recv(sock,buffer,sizeof(buffer),0) == -1)
throw "Erro ao receber resposta do servidor!";
}
/////////////////////////////////////////////////////////////////////////////////////////
int SMTP::verifica_codigo(string codigo)
{
return (int)(string(buffer,0,3) == codigo);
}
/////////////////////////////////////////////////////////////////////////////////////////
base64.h
// Algorítimo: http://www.adp-gmbh.ch/cpp/common/base64.html xD //
static const std::string base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
string base64(unsigned char const* bytes_to_encode, unsigned int in_len) {
string ret;
int i = 0;
int j = 0;
unsigned char char_array_3[3];
unsigned char char_array_4[4];
while (in_len--) {
char_array_3[i++] = *(bytes_to_encode++);
if (i == 3) {
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for(i = 0; (i <4) ; i++)
ret += base64_chars[char_array_4[i]];
i = 0;
}
}
if (i)
{
for(j = i; j < 3; j++)
char_array_3[j] = '\0';
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for (j = 0; (j < i + 1); j++)
ret += base64_chars[char_array_4[j]];
while((i++ < 3))
ret += '=';
}
return ret;
}
exemplo.cpp#include <iostream>
#ifdef WIN32
#include <winsock.h>
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#endif
using namespace std;
#include "smtp_class.h"
int main()
{
SMTP email;
try{
#ifdef WIN32
WinSock.Iniciar();
#endif
email.Conectar("smtp.servidor.lol"); // Servidor SMTP
email.Logar("LOL","LOL123"); // Usuário e senha
email.De("lol","lol@lol.com.br"); // Remetente
email.Para("amigo_do_lol@lol2.com.br"); // Destinatario
email.Assunto("HI"); // Assunto
email.Mensagem("<font color=red><b>xD</b></font>"); // Mensagem
email.Enviar(); // Enviar-a
email.Desconectar(); // Desconecta-se
#ifdef WIN32
WinSock.Terminar();
#endif
cout << "Email Enviado xD\n";
}
catch(const char * msg){ // Possíveis exceções
printf("%s\n",msg);
return 1;
}
catch(...){ // Exceções não esperadas
cout << "Ocorreu um erro inesperado no programa.";
return 1;
}
return 0;
}
Obs:
1) Para compilar o código no Windows, deve-se adicionar "-lwsock32" no linker do compilador;
Quoteex: g++ exemplo.cpp -o exemplo.exe -lwsock32
2) No Linux, não é necessário incluir parâmetros no linker.
Quoteex: g++ exemplo.cpp -o exemplo
Source + exemplo:
http://three.fsphost.com/darkside/smtp_exemplo.zip (http://three.fsphost.com/darkside/smtp_exemplo.zip)
Bye xD
cara , vc e um dos caras q mais sabem de C q eu conheço , mas particularmente eu nao uso mais c/c++ pros meus projetos por causa da mao de obra pra se fazer certas coisas , ta certo q em C vc faz tudo , aprende a "raiz" das coisas , mas eu acho q tem horas q vc precisa fazer as coisas mais rapido , e um soft simples pode tomar muito do seu tempo
see you
Realmente, Dark Side humilha!
HadeS