调用aws ses发送邮件(二)
简述
申请脱离沙盒环境后,邮件发送还有很多问题,国外邮箱包括gmail等都采用了DKIM安全验证,国内只有腾讯邮箱做了DKIM,钉钉邮箱最多只有个SPF。所以很可能导致我们发送的邮件进入别人的垃圾箱。
问题和方案
为了防止邮件在发送途中被拦截修改,一般邮件都会设置 SPF 或 DKIM 验证机制。
简单来讲,需要告诉 AWS SES 服务器我们已经取得 flitsneak.ai 域名的授权可以用 其及子域名hi@flitsneak.ai 等进行发送邮件,并且该邮件已经经过 DKIM 进行加密处理。这样 Gmail 邮箱会认为该邮件的安全性足够高才不会当成垃圾邮件或者拒收。
具体:
为了达到如上效果,需要对 flitsneak.ai 的 DNS 服务器进行相应配置,加上 DNS 的参数来取得 AWS 的信任进而不会被 Gmail 拒收,为了防备不必要的问题,需要配置 DNS 授权 ,SPF,DKIM,DMARC 这四类属性(最起码要有SPF,多多益善)。
首先需要登录到flitsneak.ai 的 DNS 服务控制平台,可能是 amazon 或者是 dreamhost 或者是其他服务商的 DNS 。 (flitsneak.ai 或者具体的子域名比如 hi.flitsneak.ai, 如果是具体的子域名下面也要相应修改 )
然后在 mella.ai 的 DNS 选项中添加这俩对应值。
添加 DNS 授权:
名称 | 类型 | 值 |
---|---|---|
_amazonses.flitsneak.ai | TXT | aws的ses domain认证域面板生成 |
添加 DKIM :
名称 | 类型 | 值 |
---|---|---|
同上生成 | CNAME | 同上生成 |
同上生成 | CNAME | 同上生成 |
同上生成 | CNAME | 同上生成 |
添加 SPF:
名称 | 类型 | 值 |
---|---|---|
@ | TXT | “v=spf1 include:flitsneak.ai include:amazonses.com ~all” |
DMARC 策略:
名称 | 类型 | 值 |
---|---|---|
_dmarc.mella.ai | TXT | “v=DMARC1;p=quarantine;pct=25;rua=mailto:dmarcreports@flitsneak.ai” |
要注意DNS授权和DKIM都是aws ses服务认证domain时自动生成的,而SPF有相应的语法规范。
java aws ses v2写法
这是aws推荐的java程序发送邮件的写法,要注意前提和上一篇v1是一致的,要脱离沙盒,要有credential。
一、引入依赖
官方建议我们版本控制:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>bom</artifactId>
<version>2.17.29</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
然后引入我们需要的ses,当然aws还有其他优秀的util也可以引入:
<!-- https://mvnrepository.com/artifact/software.amazon.awssdk/ses -->
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>ses</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.mail/javax.mail-api -->
<dependency>
<groupId>javax.mail</groupId>
<artifactId>javax.mail-api</artifactId>
<version>1.6.2</version>
</dependency>
直接放上改写的程序,因为需要在邮件和app之间传参,所以及改写的方法也加了参数:
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.ses.SesClient;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeBodyPart;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Properties;
import software.amazon.awssdk.core.SdkBytes;
import software.amazon.awssdk.services.ses.model.SendRawEmailRequest;
import software.amazon.awssdk.services.ses.model.RawMessage;
import software.amazon.awssdk.services.ses.model.SesException;
/**
* @author flitsneak
* @ClassName
* @date 2021/8/30 17:50
*/
public class SESV2 {
/**
* To run this Java V2 code example, ensure that you have setup your development environment, including your credentials.
* <p>
* For information, see this documentation topic:
* <p>
* https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/get-started.html
*/
static final String SUBJECT = "Hi";
static final String SENDER = "hi@flitsneak.ai";
public static void send(
String recipient, String UUID
) throws AddressException, MessagingException, IOException {
// The email body for non-HTML email clients
String bodyText = "Hello,\r\n" + "This is Mella. ";
// The HTML body of the email
String bodyHTML =
"<html>" +
"<body paddingwidth='0' paddingheight='0' style='padding-top: 0; padding-bottom: 0; padding-top: 0; padding-bottom: 0; background-repeat: repeat; width: 100% !important; -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; -webkit-font-smoothing: antialiased;' offset='0' toppadding='0' leftpadding='0'>" +
"<table width='100%' border='0' cellspacing='0' cellpadding='0' align='center' background='https://i.loli.net/2021/08/31/wUVbPe9oSdB8tTY.png' style='font-family:Helvetica, Arial,serif;'>" +
"</table>" +
"</body>"
+ "</html>";
Region region = Region.US_EAST_1;
SesClient client = SesClient.builder()
.region(region)
.build();
Session session = Session.getDefaultInstance(new Properties());
MimeMessage message = new MimeMessage(session);
// Add subject, from and to lines
message.setSubject(SUBJECT, "UTF-8");
message.setFrom(new InternetAddress(SENDER));
message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(recipient));
// Create a multipart/alternative child container
MimeMultipart msgBody = new MimeMultipart("alternative");
// Create a wrapper for the HTML and text parts
MimeBodyPart wrap = new MimeBodyPart();
// Define the text part
MimeBodyPart textPart = new MimeBodyPart();
textPart.setContent(bodyText, "text/plain; charset=UTF-8");
// Define the HTML part
MimeBodyPart htmlPart = new MimeBodyPart();
htmlPart.setContent(bodyHTML, "text/html; charset=UTF-8");
// Add the text and HTML parts to the child container
msgBody.addBodyPart(textPart);
msgBody.addBodyPart(htmlPart);
// Add the child container to the wrapper object
wrap.setContent(msgBody);
// Create a multipart/mixed parent container
MimeMultipart msg = new MimeMultipart("mixed");
// Add the parent container to the message
message.setContent(msg);
// Add the multipart/alternative part to the message
msg.addBodyPart(wrap);
try {
System.out.println("Attempting to send an email through Amazon SES " + "using the AWS SDK for Java...");
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
message.writeTo(outputStream);
ByteBuffer buf = ByteBuffer.wrap(outputStream.toByteArray());
byte[] arr = new byte[buf.remaining()];
buf.get(arr);
SdkBytes data = SdkBytes.fromByteArray(arr);
RawMessage rawMessage = RawMessage.builder()
.data(data)
.build();
SendRawEmailRequest rawEmailRequest = SendRawEmailRequest.builder()
.rawMessage(rawMessage)
.build();
client.sendRawEmail(rawEmailRequest);
client.close();
} catch (SesException e) {
System.err.println(e.awsErrorDetails().errorMessage());
}
}
}
邮件也有很多安全要注意,比如背景图只能用https协议,href属性也只支持https协议,只能采用原始的表格布局,仅支持内联style,不支持class标签等等。