Tutorial
Enviar e-mails com Java
Envie e-mails do Java com o SDK emailit-java ou com Spring Boot e Jakarta Mail por SMTP, e verifique os webhooks do Emailit em um controller do Spring.
Este guia mostra como enviar e-mails do Java com o SDK oficial emailit-java, como usar o starter de e-mail do Spring Boot ou o Jakarta Mail por SMTP como alternativa e como verificar webhooks em um controller do Spring.
Pré-requisitos
- Java 11 ou mais recente. Os exemplos com Spring usam o Spring Boot 3, que exige Java 17.
- Um domínio de envio verificado, por exemplo,
acme.com. - Uma chave de API. Uma chave Sending Only restrita ao seu domínio é suficiente.
- Até o seu workspace ter acesso de produção, você só pode enviar para os e-mails das contas dos membros do workspace.
Instalar o SDK
Adicione a dependência, usando a versão mais recente do repositório emailit-java:
<dependency>
<groupId>com.emailit</groupId>
<artifactId>emailit-java</artifactId>
<version>VERSION</version>
</dependency>implementation 'com.emailit:emailit-java:VERSION'Configurar a chave de API
Forneça a chave como uma variável de ambiente:
export EMAILIT_API_KEY=secret_••••••••••••••••••••••••••••••••No Spring Boot, associe-a a uma propriedade para poder injetá-la:
emailit.api-key=${EMAILIT_API_KEY}Enviar um e-mail
import com.emailit.*;
import com.emailit.exception.*;
import com.emailit.params.*;
import java.util.List;
public class SendEmail {
public static void main(String[] args) throws EmailitException {
EmailitClient emailit = new EmailitClient(System.getenv("EMAILIT_API_KEY"));
EmailSendParams params = EmailSendParams.builder()
.setFrom("Acme <hello@acme.com>")
.setTo(List.of("ada@example.com"))
.setSubject("Your order has shipped")
.setHtml("<p>Order #1042 is on its way.</p>")
.build();
EmailitObject email = emailit.emails().send(params);
System.out.println(email.getString("id")); // em_…
}
}No Spring Boot, registre o cliente uma vez como bean e injete-o onde você envia:
import com.emailit.EmailitClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class EmailitConfig {
@Bean
EmailitClient emailitClient(@Value("${emailit.api-key}") String apiKey) {
return new EmailitClient(apiKey);
}
}Tratar erros
O SDK lança exceções tipadas que estendem EmailitException:
try {
emailit.emails().send(params);
} catch (RateLimitException e) {
// 429: back off and retry
} catch (AuthenticationException e) {
// 401: the API key is missing or invalid
} catch (UnprocessableEntityException e) {
// 422: for example, the from domain isn't verified
} catch (EmailitException e) {
log.error("Emailit error {}: {}", e.getHttpStatus(), e.getHttpBody());
}Enviar por SMTP como alternativa
Spring Boot
Adicione spring-boot-starter-mail e configure o relay:
spring.mail.host=smtp.emailit.com
spring.mail.port=587
spring.mail.username=emailit
spring.mail.password=${EMAILIT_API_KEY}
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=trueDepois, envie com JavaMailSender:
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;
@Service
public class WelcomeMailer {
private final JavaMailSender mailSender;
public WelcomeMailer(JavaMailSender mailSender) {
this.mailSender = mailSender;
}
public void sendWelcome(String to) {
SimpleMailMessage message = new SimpleMailMessage();
message.setFrom("Acme <hello@acme.com>");
message.setTo(to);
message.setSubject("Welcome to Acme");
message.setText("Thanks for signing up.");
mailSender.send(message);
}
}Use MimeMessageHelper para HTML e anexos.
Jakarta Mail sem Spring
O Jakarta Mail puro (antigo JavaMail) usa as mesmas propriedades mail.smtp.*:
Properties props = new Properties();
props.put("mail.smtp.host", "smtp.emailit.com");
props.put("mail.smtp.port", "587");
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.starttls.enable", "true");
props.put("mail.smtp.starttls.required", "true");
Session session = Session.getInstance(props, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("emailit", System.getenv("EMAILIT_API_KEY"));
}
});Se a porta 587 estiver bloqueada na sua rede, use 2525 ou 2587 com as mesmas configurações. Consulte Configurações de SMTP.
Receber webhooks
Crie um webhook e guarde o segredo de assinatura dele em EMAILIT_WEBHOOK_SECRET. Receba o corpo como String para verificar exatamente o que o Emailit assinou:
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.HexFormat;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RestController
public class EmailitWebhookController {
private final ObjectMapper mapper = new ObjectMapper();
private final String secret = System.getenv("EMAILIT_WEBHOOK_SECRET");
@PostMapping("/webhooks/emailit")
public ResponseEntity<Void> receive(
@RequestBody String body,
@RequestHeader(value = "X-Emailit-Signature", defaultValue = "") String signature,
@RequestHeader(value = "X-Emailit-Timestamp", defaultValue = "0") long timestamp) throws Exception {
if (Math.abs(System.currentTimeMillis() / 1000 - timestamp) > 300 || !isValid(body, signature, timestamp)) {
return ResponseEntity.status(401).build();
}
// The body is a JSON array of up to 100 events.
for (JsonNode event : mapper.readTree(body)) {
if ("email.bounced".equals(event.path("type").asText())) {
String address = event.path("data").path("object").path("to").asText();
// Stop emailing this address.
}
}
return ResponseEntity.ok().build();
}
private boolean isValid(String body, String signature, long timestamp) throws Exception {
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
byte[] digest = mac.doFinal((timestamp + "." + body).getBytes(StandardCharsets.UTF_8));
String expected = HexFormat.of().formatHex(digest);
return MessageDigest.isEqual(
expected.getBytes(StandardCharsets.UTF_8),
signature.getBytes(StandardCharsets.UTF_8));
}
}Se o Spring Security estiver ativado, libere esse caminho e exclua-o da proteção contra CSRF. Retorne um 2xx em até 30 segundos; as outras respostas recebem novas tentativas. Consulte Assinatura das requisições.
Dicas para produção
- Reutilize os clientes. Crie um único
EmailitClient(ou use oJavaMailSenderúnico do Spring) em vez de um por mensagem. - Envie de forma assíncrona. Use
@Async, uma fila de mensagens ou um job agendado para e-mails em massa e limite a vazão para ficar dentro dos seus limites de envio (2 e-mails por segundo por padrão). - Torne as novas tentativas seguras. Se você tentar de novo depois de um timeout, envie um cabeçalho
Idempotency-Keycomjava.net.http.HttpClient; consulte Idempotência. - Elimine webhooks duplicados guardando cada
event_idque você processa.