Servidor de Email

Pessoal,

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.

Alguém poderia por favor me dar alguma luz?

Obrigado.

tem um exemplo nesse site: http://www.rblasch.org/studies/cs629/pa2/index.html

o ideal é debugar pra entender :wink:

cara,

existe um projeto que se chama James, da uma olhada nele.

t+

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.

Obrigado pela rápida resposta de todos.

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.

Muito obrigado novamente pela ajuda de todos.

Abraços

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.

Abraços.

Não use o GMail para fazer testes ainda - como ele usa SSL, é bem complexo você se autenticar nele. Use algum outro servidor de email para testar.

Boa tarde entanglement,

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.

Obrigado.

Alguma idéia?