Estou com um projeto na disciplina de Redes para criar um servidor de E-mail implementando os protocolos de conexão (sem uso de API’s)
Não conheço muito bem o uso de sockets em Java por isso pedi ajuda a alguns amigos, um deles me mandou esse exemplo:
package smtp.exemplo;
import java.io.*;
import java.net.*;
import java.util.*;
import java.text.*;
public class SmtpSender {
private Socket smtpSocket = null;
private DataOutputStream os = null;
private DataInputStream is = null;
private boolean podeEnviar=false;
Date dDate = new Date();
DateFormat dFormat = DateFormat.getDateInstance(DateFormat.FULL,Locale.US);
public SmtpSender(String m_sHostName, int m_iPort){
try
{ // Open port to server
smtpSocket = new Socket(m_sHostName, m_iPort);
os = new DataOutputStream(smtpSocket.getOutputStream());
is = new DataInputStream(smtpSocket.getInputStream());
if(smtpSocket != null && os != null && is != null)
{ // Connection was made. Socket is ready for use.
podeEnviar = true;
}
}
catch(Exception e)
{ System.out.println("Host " + m_sHostName + "unknown"); }
}
public boolean Enviar(String From, String To, String CC, String Subject, String sMessage){
if(!podeEnviar)
return false;
try
{ os.writeBytes("HELO\r\n");
// You will add the email address that the server
// you are using know you as.
os.writeBytes("MAIL From: " + From + "\r\n");
// Who the email is going to.
os.writeBytes("RCPT To:"+ To +"\r\n");
//IF you want to send a CC then you will have to add this
os.writeBytes("RCPT Cc:" + CC + "\r\n");
// Now we are ready to add the message and the
// header of the email to be sent out.
os.writeBytes("DATA\r\n");
os.writeBytes("X-Mailer: Via Java\r\n");
os.writeBytes("DATE: " + dFormat.format(dDate) + "\r\n");
os.writeBytes("From: " + From + "\r\n");
os.writeBytes("To: " + To + "\r\n");
//Again if you want to send a CC then add this.
//os.writeBytes("Cc: CCDUDE <CCPerson@theircompany.com>\r\n");
//Here you can now add a BCC to the message as well
//os.writeBytes("RCPT Bcc: BCCDude<BCC@invisiblecompany.com>\r\n");
//sMessage = "Your subjectline.";
os.writeBytes("Subject: " + Subject + "\r\n");
os.writeBytes(sMessage + "\r\n");
os.writeBytes("\r\n.\r\n");
os.writeBytes("QUIT\r\n");
// Now send the email off and check the server reply.
// Was an OK is reached you are complete.
String responseline;
while((responseline = is.readLine())!=null)
{ System.out.println(responseline);
if(responseline.indexOf("Ok") != -1)
break;
}
return true;
}
catch(Exception e)
{
System.out.println("Cannot send email as an error occurred.");
return false;
}
}
}
Parecia ser exatamente o necessário para eu me basear e apenas modificar poucas coisas, porém não estou conseguindo realizar a conexão pois não vejo forma de autenticação.
O objetivo é através de um socket enviar uma mensagem para algum servidor de e-mail real (gmail por ex.), não sendo necessário receber retorno.
Se eu tivesse de implementar um cliente SMTP e POP3 só com sockets, eu usaria, para criar um servidor próprio de email, o James (que já foi citado acima).
É muito, muito, muito mais fácil de se conectar que ao GMail (que usa o protocolo SSL e é muito complexo de se conectar, mesmo usando o JavaMail).
Para criar um servidor SMTP e POP3 só com sockets é um bocadinho mais complicado, mas de qualquer forma use o James como referência.
Estou baixando o james, não conhecia.
Vou me basear nele para tentar fazer o servidor, o link que o douglaskd ajudou bastante também, o código ta muito bem explicado, acredito que com alguma modificação simples rode bem também.
Irei tentar fazer isso agora e logo mais posto a resposta por aqui.
Pessoal, consegui em parte fazer o código porém estou com problemas na parte da autenticação.
Dei um debug no código e ele trava na linha do laço
while(linhaResposta!=null)
//Imprimir na tela o conteúdo de linhaResposta
{ System.out.println(linhaResposta);
linhaResposta = mf.readLine();
}
Segue abaixo o código completo.
//Bibliotecas que precisamos utilizar.
import java.io.*; // Precisamos para utilizar DataOutputStream/DataInputStream
import java.net.*; // Precisamos para poder criar um objeto socket
import java.util.*;// Precisamos para utilizar a classe Date
import java.text.*; //Precisamos para utilizar a classe DateFormat
import javax.net.ssl.*;// Precisamos para poder utilizar autenticação via SSL (SSLSocket)
//Definição da classe EnviarEmailSmtp
public class EnviarEmailSmtp
{
private Socket smtpSocket = null; //Varável smtpSocket do tipo Socket sendo inicializado como nulo (vazio)
private DataOutputStream kk = null; //Objeto kk do tipo DataOutputStream sendo inicializado como nulo (vazio)
private BufferedReader mf = null; //Objeto mf do tipo DataInputStream sendo inicializado como nulo (vazio)
private boolean podeEnviar=false;//Variável privada podeEnviar do tipo boolean sendo inicializada como false
Date data = new Date();// Objeto data do tipo Date
//Objeto dFormatada do tipo DateFormat, necessário para modificar a forma como irá mostrar a data
//Obs. Não consegui localizar no formato pt-br (perguntar a Glauco)
DateFormat dFormatada = DateFormat.getDateInstance(DateFormat.FULL,Locale.US);
//Método EnviarEmailSmtp tendo como argumentos uma varável servidor do tipo String e uma variável porta do tipo int)
public EnviarEmailSmtp(String servidor, int porta)
{
//tente
try
{
//Abrindo porta do servidor
//criando um objeto "smtpSocket" do tipo Socket
smtpSocket = new Socket(servidor, porta);
//smtpSocket = new Socket(servidor, porta);
//objeto "kk" do tipo DataOutputStream utilizada para saída do fluxo de dados
kk = new DataOutputStream(smtpSocket.getOutputStream());
//objeto "mf" do tipo DataInputStream utilizada para entrada do fluxo de dados
mf = new BufferedReader (new InputStreamReader(smtpSocket.getInputStream()));
//Se smtpSocket for diferente de vazio (nulo) e kk for diferente de vazio (nulo) e mf for diferente de vazio(nulo)
if(smtpSocket != null && kk != null && mf != null)
{
//Conexão ja está ativa, socket pronto para uso.
podeEnviar = true;
//O objeto kk utiliza o método writeBytes para escrever (enviar) a mensagem "EHLO"
kk.writeBytes("EHLO\r\n");
// Adicionar o email
//variável linhaResposta do tipo String
String linhaResposta = mf.readLine();
//linhaResposta é igual a mf.readLine(entrada de dados) enquanto mf for diferente de vazio (nulo)
while(linhaResposta!=null)
//Imprimir na tela o conteúdo de linhaResposta
{ System.out.println(linhaResposta);
linhaResposta = mf.readLine();
}
//O objeto kk inicia a comunicação (escrita) através da tag STARTTLS (Conexão via SSL/TSL)
kk.writeBytes("STARTTLS\r\n");
//imprimir na tela SSLSocket
System.out.println("SSLSocket");
InetAddress a = smtpSocket.getInetAddress();
String host = a.getHostName();
int portaa = smtpSocket.getPort();
SSLSocketFactory factory = (SSLSocketFactory) SSLSocketFactory.getDefault();
smtpSocket = factory.createSocket(smtpSocket, host, portaa, true);
}
}
//pegar (se ouver erro através do objeto k do tipo Exception)
catch(Exception k)
{
//Imprimir mensagem "Host + servidor + Desconhecido"
System.out.println("Host " + servidor + "Desconhecido");
}
}
//Método Enviar recebendo como parâmetros (argumentos/atribitos) as variáveis "de", "para", "CC", "assunto" e "mensagem" todas do tipo String.
public boolean Enviar(String de, String para, String CC, String assunto, String mensagem)
{
//Se for diferente de podeEnviar (que inicialmente está setada como true)
if(!podeEnviar)
return false;//retorne false (Logo, não poderemos enviar)
try//Tente
{
//O objeto kk utiliza o método writeBytes para escrever o parâmetro de E-mail
kk.writeBytes("E-mail de: <" + de + ">\r\n");
// Para quem vai o e-mail
kk.writeBytes("RCPT Para: <"+ para +">\r\n");
//Se formos utilizar com cópia
kk.writeBytes("RCPT Cc:<" + CC + ">\r\n");
kk.writeBytes("DATA\r\n");
kk.writeBytes("Faculdade Nova Roma: Via Eclipse\r\n");
kk.writeBytes("Data: " + dFormatada.format(data) + "\r\n");
kk.writeBytes("De: <" + de + ">\r\n");
kk.writeBytes("Para: <" + para + ">\r\n");
kk.writeBytes("Assunto: " + assunto + "\r\n");
kk.writeBytes(mensagem + "\r\n");
kk.writeBytes("\r\n.\r\n");
kk.writeBytes("Sair\r\n");
// Verificar se o e-mail foi enviado.
// Se obtivermos ok o processo foi realizado.
String linhaResposta; // Variável linhaResposta do tipo String
//linhaResposta é igual a mf.readLine(entrada de dados) enquanto mf for diferente de vazio (nulo)
while((linhaResposta = mf.readLine())!=null)
{
//imprime o conteúdo de linhaResposta
System.out.println(linhaResposta);
//Se
//Verifica a posição em que a String se encontra.
if(linhaResposta.indexOf("Ok") != -1)
break;// Pare
}
return true;//Retorne true
}
//Pegar a exceção através do objeto m do tipo Exception
catch(Exception m)
{
//Imprime a mensagem de erro
System.out.println("O e-mail não pode ser enviado, ocorreu algum erro.");
return false;//Retorna falso
}
}
public static void main(String [] args)
{
EnviarEmailSmtp envio = new EnviarEmailSmtp("smtp.gmail.com", 25);
envio.Enviar("André", "João", "Teste", "Redes", "Testando Servidor");
}
}
Alguém tem alguma idéia? preciso fazer a autenticação no servidor para poder enviar o e-mail, li sobre SSLSocketFactory e tentei implementar porém não estou conseguindo.
Está com alguns comentários pois irei repassar a classe para a equipe do projeto adiante.
O prof° que nos passou o exercício solicitou que fizéssemos isso com algum servidor mais não definiu explicitamente qual, estou tentando com o gmail por ser um “e-mail padrão”
porém você saberia de algum cuja conexão não utilizasse SSL/TSL?
realmente estou sem mais idéias de como passar daí, ja li várias vezes a RFC do SMTP e ESMTP porém não entendo como avançar sem a resposta do servidor.
Alguém teria algum exemplo?
A idéia é enviar um e-mail p algum servidor real via socket, com alguma ajuda consegui construir esse + trava na parte que citei acima.