sexta-feira, 5 de abril de 2013

Como enviar emails usando JavaMail

Neste post, vou apresentar como enviar um email através de uma servlet. 

Como de costume, criamos um projeto web dinâmico no eclipse, com, por exemplo, o nome "EnviarEmailServlet".

Para implementar este tutorial será necessária  a biblioteca JavaMail. A biblioteca pode ser encontrada no site da OracleNota: A menos que você esteja usando Java SE 6 ou mais recente, você também vai precisar da JavaBeans Activation Framework (JAF) que fornece o pacote javax.activation.

Depois de fazer o download, copie o arquivo mail.jar para a pasta lib do seu projeto.

O código-fonte da página index.jsp que contém o formulário para o envio do e-mail é:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<title>Enviar E-Mail</title>
</head>
<body>

    <h1>Enviar E-Mail</h1>
    <form action="sendEmail.do" method="post">
        <table>
            <tr>
                <td>De</td>
                <td><input type="text" name="from" /></td>
            </tr>
            <tr>
            <tr>
                <td>Para</td>
                <td><input type="text" name="to" /></td>
            </tr>
            <tr>
                <td>Assunto</td>
                <td><input type="text" name="subject" /></td>
            </tr>
            <tr>
                <td>Mensagem</td>
                <td><textarea cols="25" rows="8" name="message"></textarea></td>
            </tr>
        </table>
        <br /> <input type="submit" value="Enviar" />
    </form>
</body>
</html>

Para receber estes parâmetros e enviar o e-mail devemos implementar uma servlet. Esta servlet vai se chamar SendEmail. Eu sobrescrevi o método init() da servlet para pegar os parâmetros necessários para o envio do email. A servlet deve conter o seguinte código:

package org.andvicoso.javamail.controller;

import java.io.IOException;
import java.util.Date;
import java.util.Properties;

import javax.mail.AuthenticationFailedException;
import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/sendEmail.do")
public class SendEmail extends HttpServlet {

    private static final String MSG_MIME_TYPE = "text/plain";

    private String host;
    private String port;
    private String login;
    private String password;

    @Override
    public void init() throws ServletException {
        ServletContext context = getServletContext();
        host = context.getInitParameter("host");
        port = context.getInitParameter("port");
        login = context.getInitParameter("login");
        password = context.getInitParameter("password");
    }

    protected void doPost(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        String resultMsg = "E-Mail enviado com sucesso!";
        String from = request.getParameter("from");
        String to = request.getParameter("to");
        String subject = request.getParameter("subject");
        String message = request.getParameter("message");

        try {
            Properties props = getSMTPProperties();

            Authenticator auth = new SMTPAuthenticator(login, password);

            Session session = Session.getInstance(props, auth);

            MimeMessage msg = createMessage(from, to, subject, message, session);

            Transport.send(msg);
        } catch (AuthenticationFailedException ex) {
            resultMsg = "Falha na autenticação";
        } catch (AddressException ex) {
            resultMsg = "E-Mail de destino inválido!";
        } catch (MessagingException ex) {
            resultMsg = ex.getMessage();
            //ex.printStackTrace();//descomentar para debug
        }

        request.setAttribute("message", resultMsg);

        RequestDispatcher dispatcher = request
                .getRequestDispatcher("result.jsp");
        dispatcher.forward(request, response);
    }

    private MimeMessage createMessage(String from, String to, String subject,
            String message, Session session) throws MessagingException {
        MimeMessage msg = new MimeMessage(session);
        msg.setText(message);
        msg.setSubject(subject);
        msg.setFrom(new InternetAddress(from));
        msg.addRecipient(Message.RecipientType.TO, new InternetAddress(to));
        msg.setContent(message, MSG_MIME_TYPE);
        msg.setSentDate(new Date());

        return msg;
    }

    private Properties getSMTPProperties() {
        Properties props = new Properties();
        props.setProperty("mail.host", host);
        props.setProperty("mail.transport.protocol", "smtp");
        // Comente essas 4 linhas abaixo se deseja usar o SSL
        props.setProperty("mail.smtp.auth", "true");
        props.setProperty("mail.smtp.port", port);
        props.setProperty("mail.smtp.ssl.trust", host);
        props.setProperty("mail.smtp.starttls.enable", "true");
        // Descomente essas tres linhas abaixo se deseja usar SSL
//         props.setProperty("mail.smtps.auth", "true");
//         props.setProperty("mail.smtps.port", port);
//         props.setProperty("mail.smtps.ssl.trust", host);
        //Descomente a linha abaixo se deseja informações de debug
//        props.put("mail.debug", "true");

        return props;
    }

    private class SMTPAuthenticator extends Authenticator {
        private String login;
        private String password;

        public SMTPAuthenticator(String login, String password) {
            this.login = login;
            this.password = password;
        }

        public PasswordAuthentication getPasswordAuthentication() {
            return new PasswordAuthentication(login, password);
        }
    }
}

Se você preferir para criptografar suas conexões com SSL, então certifique-se de suas propriedades incluam SMTPS em vez de SMTP e que a propriedade mail.smtps.ssl.trust seja definida.

Para enviar e-mail para vários destinatários apenas adicionar mais endereços através do método  addRecipient.

Para anexar um ou mais arquivos no e-mail devemos alterar o tipo do conteúdo do e-mail para MimeMultipart na função createMessage.

Segue o código para isso:

    // cria uma parte do corpo da mensagem como sendo o texto
    MimeBodyPart messageBodyPart = new MimeBodyPart();
    // preenche a mensagem do e-mail
    messageBodyPart.setText(message);

    Multipart multipart = new MimeMultipart();
    multipart.addBodyPart(messageBodyPart);

    // a segunda parte do corpo é o anexo
    messageBodyPart = new MimeBodyPart();
    DataSource source = new FileDataSource(fileAttachment);//esse fileAttachment é caminho para o arquivo!
    messageBodyPart.setDataHandler(new DataHandler(source));
    messageBodyPart.setFileName(fileAttachment);
    multipart.addBodyPart(messageBodyPart);

    // seta o conteúdo da mensagem como sendo o multipart criado (texto+arquivo)
    msg.setContent(multipart);//ao invés de msg.setContent(message, MSG_MIME_TYPE);

Uma outra ideia interessante é usar um arquivo properties para armazenar as propriedades do servidor SMTP.

Para armazenar os parâmetros necessários para a conexão com o servidor SMTP eu adicionei parâmetros de contexto no web.xml. Desta maneira:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
        http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    id="WebApp_ID" version="3.0">
    <display-name>JavaMail</display-name>

    <!-- SMTP settings -->
    <context-param>
        <param-name>host</param-name>
        <param-value>smtp.gmail.com</param-value>
        <!-- ou outro se não for gmail -->
    </context-param>

    <context-param>
        <param-name>port</param-name>
        <param-value>587</param-value>
        <!-- O padrão é 25. Podemos usar a 26 se o ISP bloquear a 25 -->
    </context-param>

    <context-param>
        <param-name>login</param-name>
        <param-value>abc@gmail.com</param-value>
        <!-- ou outro email se não for gmail -->
    </context-param>

    <context-param>
        <param-name>password</param-name>
        <param-value>abc</param-value>
        <!-- colocar a senha do email -->
    </context-param>

    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
</web-app>

Altere os valores parâmetros no web.xml para os seus valores e depois é só testar!

Para este exemplo também é possível encontrar um projeto exemplo no meu dropbox.

Até o próximo post!

[]`s

segunda-feira, 1 de abril de 2013

Criando um template para web site usando Sitemesh 3

Criando um template para web site usando Sitemesh 3


Este post vai apresentar como implementar um template para web site usando a biblioteca Sitemesh 3.

Para este exemplo, vou criar um projeto web dinâmico no Eclipse. O nome pode ser TemplateSitemesh3 por exemplo.

Para implementar o exemplo precisamos da biblioteca sitemesh na versão 3, que é encontrada em:
Baixe o zip da biblioteca, descompacte, procure o arquivo sitemesh-3.0-alpha-2.jar dentro do diretório e copie ele para a pasta lib dentro de WebContent do seu projeto.

Depois de copiar a biblioteca, crie um arquivo chamado sitemesh3.xml dentro do diretório WEB-INF. Este arquivo serve para configurar qual o arquivo que será considerado o template da aplicação (chamado de decorator) e quais arquivos não vão ser considerados pelo template, como por exemplo, arquivos CSS, imagens, JavaScripts e etc. Neste exemplo eu vou usar como decorator o arquivo /WEB-INF/decorators/main.jsp e vou excluir da "decoração" os arquivos de estilos, imagens e JavaScripts. O código do arquivo sitemesh3.xml fica assim:


<sitemesh>
    <mapping decorator="/WEB-INF/decorators/main.jsp" />
    <!-- Excluir o caminho da decoracao. -->
    <mapping path="/images/*" exclue="true" />
    <mapping path="/javascript/*" exclue="true" />
    <mapping path="/styles/*" exclue="true" />
</sitemesh>

Para mais informações sobre filtros, acesse o link: da caelum ou da oracle. Ou ainda o livro "Use a cabeça: Servlets e JSP".

Em seguida, devemos definir no web.xml um filtro do Sitemesh que vai tratar todas as requisições e aplicar o template sobre elas.

    <filter>
        <filter-name>sitemesh</filter-name>
        <filter-class>org.sitemesh.config.ConfigurableSiteMeshFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>sitemesh</filter-name>
        <url-pattern>/*</url-pattern>
        <dispatcher>REQUEST</dispatcher>
        <dispatcher>FORWARD</dispatcher>
        <dispatcher>INCLUDE</dispatcher>
    </filter-mapping>

Todas as páginas html e jsp que serão criadas neste projeto deverão passar pelo filtro do Sitemesh que irá "decorar" as páginas com o decorator. Assim todas essas páginas não deverão conter (repetir) as partes comuns do template, tais como: header, footer, menu e etc.

Agora vou mostrar um código de exemplo para o arquivo main.jsp, que é o nosso decorator. Ele deve estar localizado no diretório /WEB-INF/decorators/ . Segue o código:


<%@ page contentType="text/html; charset=utf-8" pageEncoding="utf-8" trimDirectiveWhitespaces="true" %>
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" view="width=device-width, initial-scale=1.0">
    <meta http-equiv="Content-Type" view="text/html; charset=utf-8" />
    <meta http-equiv="Content-Language" view="pt-BR" />
    
    <link href="styles/default.css" rel="stylesheet">
    
    <title>TemplateSitemesh3 - <sitemesh:write property="title" /></title>
    
    <sitemesh:write property="head" />
</head>
<body>
    <jsp:include page="template/header.jsp" />
    
    <sitemesh:write property="body" />

    <jsp:include page="template/footer.jsp" />
    <!-- javascript -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="scripts/jquery/jquery.js"></script>
</body>
</html>

Neste exemplo, eu mostro como referenciar um arquivo CSS e um JavaScript. Lembrando que no seu projeto devem ser alterados os caminhos para os arquivos relativos correspondentes. Vale o mesmo para os comandos jsp:include onde eu incluo o header e footer, que não são apresentados neste exemplo, mas ambos contêm código JSP comum.

A linha de código <sitemesh:write property="head" />  indica que ao "decorar" a página o sitemesh vai copiar o cabeçalho (head) da página corrente e colar na página "decorada" final. A mesma coisa acontece com o comando <sitemesh:write property="body" />, só que adicionando o conteúdo do corpo (body) da página corrente. Já a instrução <sitemesh:write property="title" /> copia o título da página sendo decorada para a tag title do head da página final.

Bom, acho que é só! Daqui pra frente é só criar as suas páginas de view (HTMLs e JSPs) normalmente e testar. É possível baixar o projeto do eclipse de exemplo do meu dropbox.
Qualquer dúvida ou comentário, é só falar!

Popular Posts

StackOverflow Profile


profile for andvicoso at Stack Overflow, Q&A for professional and enthusiast programmers