將電子郵件用於支持應用程序的新方法:AWS 教程

已發表: 2022-03-11

電子郵件可能不像其他通信平台那麼酷,但使用它仍然很有趣。 我最近的任務是在移動應用程序中實現消息傳遞。 唯一的問題是實際的交流需要通過電子郵件進行。 我們希望應用用戶能夠與支持團隊進行交流,就像您發送短信一樣。 支持團隊成員需要通過電子郵件接收這些消息,並且還需要能夠回復原始用戶。 對於最終用戶來說,一切都需要像任何其他現代消息傳遞應用程序一樣外觀和功能。

在本文中,我們將了解如何使用 Java 和一些 Amazon 的 Web 服務來實現與上述服務類似的服務。 您將需要一個有效的 AWS 賬戶、一個域名以及對您最喜歡的 Java IDE 的訪問權限。

基礎設施

在我們編寫任何代碼之前,我們將設置路由和使用電子郵件所需的 AWS 服務。 我們將使用 SES 發送和使用電子郵件,使用 SNS+SQS 路由傳入消息。

使用 AWS 以編程方式使用電子郵件

使用 Amazon SES 重振支持應用程序中的電子郵件。
鳴叫

一切從 SES 開始。 首先登錄您的 AWS 賬戶並導航到 SES 控制台。

在我們開始之前,您需要一個經過驗證的域名,您可以從中發送電子郵件。

這將是域應用程序用戶將發送電子郵件和支持成員將回复的。 使用 SES 驗證域是一個簡單的過程,可以在此處找到更多信息。

如果這是您第一次使用 SES,或者您沒有請求發送限制,您的帳戶將被沙盒化。 這意味著您將無法向未經 AWS 驗證的地址發送電子郵件。 當我們向虛構的幫助台發送電子郵件時,這可能會導致教程稍後出現錯誤。 為避免這種情況,您可以在電子郵件地址選項卡的 SES 控制台中驗證您計劃用作幫助台的任何電子郵件地址。

一旦您擁有經過驗證的域,我們就可以創建一個規則集。 導航到 SES 控制台中的規則集選項卡並創建一個新的收據規則。

創建接收規則的第一步是定義接收者。

收件人過濾器將允許您定義 SES 將使用哪些電子郵件,以及如何處理每條傳入消息。 我們在此處定義的收件人需要與發送電子郵件的應用程序用戶消息的域和地址模式相匹配。 這裡最簡單的情況是為我們之前驗證的域添加一個收件人,在我們的例子中是example.com 。 這將配置 SES 以將我們的規則應用於發送到example.com的所有電子郵件。 (例如 [email protected][email protected])。

要為我們的整個域創建規則,我們將為example.com添加一個收件人。

也可以匹配地址模式。 如果您想將傳入消息路由到不同的 SQS 隊列,這很有用。

假設我們有隊列 A 和隊列 B。我們可以添加兩個收件人: [email protected][email protected] 。 如果我們想將消息插入隊列 A,我們會發送電子郵件至 [email protected]。 其中的 a 部分將匹配我們的[email protected]收件人。 +和@之間的都是任意用戶數據,不會影響SES的地址匹配。 要插入隊列 B,只需將 a 替換為 b。

定義收件人後,下一步是配置 SES 在使用新電子郵件後將執行的操作。 我們最終希望這些最終出現在 SQS 中,但是目前無法直接從 SES 轉到 SQS。 為了彌補差距,我們需要使用 SNS。 選擇 SNS 操作並創建一個新主題。 我們最終將配置此主題以將消息插入 SQS。

選擇創建 SNS 主題並為其命名。

創建主題後,我們需要選擇消息編碼。 我將使用 Base64 來保留特殊字符。 當我們在服務中使用消息時,您選擇的編碼將影響消息的解碼方式。

一旦設置了規則,我們只需要命名它。

下一步將配置 SQS 和 SNS,為此我們需要前往 SQS 控制台並創建一個新隊列。

為簡單起見,我使用與我們的 SNS 主題相同的名稱。

在我們定義了我們的隊列之後,我們需要調整它的訪問策略。 我們只想授予我們的 SNS 主題插入權限。 我們可以通過添加與我們的 SNS 主題 arn 匹配的條件來實現這一點。

值字段應填充 SES 正在通知的 SNS 主題的 ARN。

設置 SQS 後,是時候再次返回 SNS 控制台以配置您的主題以將通知插入到您閃亮的新 SQS 隊列中。

在 SNS 控制台中,選擇 SES 正在通知的主題。 從那裡,創建一個新訂閱。 訂閱協議應該是 Amazon SQS,目標應該是您剛剛生成的 SQS 隊列的 ARN。

畢竟,等式的 AWS 方面應該全部設置好。 我們可以通過給自己發電子郵件來測試我們的工作。 向配置了 SES 的域發送一封電子郵件,然後前往 SQS 控制台並選擇您的隊列。 您應該能夠看到包含您的電子郵件的有效負載。

處理電子郵件的 Java 服務

現在進入有趣的部分! 在本節中,我們將創建一個能夠發送消息和處理傳入電子郵件的簡單微服務。 第一步將定義一個 API,它將代表用戶向我們的支持台發送電子郵件。

速記。 我們將專注於該服務的業務邏輯組件,不會定義 REST 端點或持久層。

要構建 Spring 服務,我們將使用 Spring Boot 和 Maven。 我們可以使用 Spring Initializer 為我們生成一個項目,start.spring.io。

首先,我們的 pom.xml 應該如下所示:

 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.toptal.tutorials</groupId> <artifactId>email-processor</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>email-processor</name> <description>A simple "micro-service" for emailing support on behalf of a user and processing replies</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.3.5.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>

代表用戶發送電子郵件支持

首先,讓我們定義一個 bean,用於代表用戶向我們的支持台發送電子郵件。 此 bean 的工作是處理來自用戶 ID 的傳入消息,並將該消息通過電子郵件發送到我們預定義的支持台電子郵件地址。

讓我們從定義一個接口開始。

 public interface SupportBean { /** * Send a message to the application support desk on behalf of a user * @param fromUserId The ID of the originating user * @param message The message to send */ void messageSupport(long fromUserId, String message); }

和一個空的實現:

 @Component public class SupportBeanSesImpl implements SupportBean { /** * Email address for our application help-desk * This is the destination address user support emails will be sent to */ private static final String SUPPORT_EMAIL_ADDRESS = "[email protected]"; @Override public void messageSupport(long fromUserId, String message) { //todo: send an email to our support address } }

讓我們也將 AWS SDK 添加到我們的 pom 中,我們將使用 SES 客戶端發送我們的電子郵件:

 <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-java-sdk</artifactId> <version>1.11.5</version> </dependency>

我們需要做的第一件事是生成一個電子郵件地址來發送我們用戶的消息。 我們生成的地址將在我們服務的消費端發揮關鍵作用。 它需要包含足夠的信息以將幫助台的回复路由回原始用戶。

為此,我們將在生成的電子郵件地址中包含原始用戶 ID。 為了保持簡潔,我們將創建一個包含用戶 ID 的對象,並使用它的 Base64 編碼 JSON 字符串作為電子郵件地址。

讓我們創建一個負責將用戶 ID 轉換為電子郵件地址的新 bean。

 public interface UserEmailBean { /** * Returns a unique per user email address * @param userID Input user ID * @return An email address unique for the input userID */ String emailAddressForUserID(long userID); }

讓我們通過添加所需的同意和一個簡單的內部類來開始我們的實現,這將幫助我們序列化我們的 JSON。

 @Component public class UserEmailBeanJSONImpl implements UserEmailBean { /** * The TLD for all our generated email addresses */ private static final String EMAIL_DOMAIN = "example.com"; /** * com.fasterxml.jackson.databind.ObjectMapper used to create a JSON object including our user ID */ private final ObjectMapper objectMapper = new ObjectMapper(); @Override public String emailAddressForUserID(long userID) { //todo: create the email address return null; } /** * Simple helper class we will serialize. * The JSON representation of this class will become our user email address */ private static class UserDetails{ private Long userID; public Long getUserID() { return userID; } public void setUserID(Long userID) { this.userID = userID; } } }

生成我們的電子郵件地址很簡單,我們需要做的就是創建一個 UserDetails 對象並對 JSON 表示進行 Base64 編碼。 我們的 createAddressForUserID 方法的完成版本應該如下所示:

 @Override public String emailAddressForUserID(long userID) { UserDetails userDetails = new UserDetails(); userDetails.setUserID(userID); //create a JSON representation. String jsonString = objectMapper.writeValueAsString(userDetails); //Base64 encode it String base64String = Base64.getEncoder().encodeToString(jsonString.getBytes()); //create an email address out of it String emailAddress = base64String + "@" + EMAIL_DOMAIN; return emailAddress; }

現在我們可以返回 SupportBeanSesImpl 並更新它以使用我們剛剛創建的新電子郵件 bean。

 private final UserEmailBean userEmailBean; @Autowired public SupportBeanSesImpl(UserEmailBean userEmailBean) { this.userEmailBean = userEmailBean; } @Override public void messageSupport(long fromUserId, String message) throws JsonProcessingException { //user specific email String fromEmail = userEmailBean.emailAddressForUserID(fromUserId); }

要發送電子郵件,我們將使用 AWS 開發工具包中包含的 AWS SES 客戶端。

 /** * SES client */ private final AmazonSimpleEmailService amazonSimpleEmailService = new AmazonSimpleEmailServiceClient( new DefaultAWSCredentialsProviderChain() //see http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/DefaultAWSCredentialsProviderChain.html );

我們正在使用 DefaultAWSCredentialsProviderChain 為我們管理憑證,此類將搜索此處定義的 AWS 憑證。

我們將使用預置的 AWS 訪問密鑰訪問 SES 並最終訪問 SQS。 有關更多信息,請查看來自 Amazon 的文檔。

下一步將使用 AWS 開發工具包將我們的messageSupport方法更新為電子郵件支持。 SES SDK 使這成為一個簡單的過程。 完成的方法應如下所示:

 @Override public void messageSupport(long fromUserId, String message) throws JsonProcessingException { //User specific email String fromEmail = userEmailBean.emailAddressForUserID(fromUserId); //create the email Message supportMessage = new Message( new Content("New support request from userID " + fromUserId), //Email subject new Body().withText(new Content(message)) //Email body, this contains the user's message ); //create the send request SendEmailRequest supportEmailRequest = new SendEmailRequest( fromEmail, //From address, our user's generated email new Destination(Collections.singletonList(SUPPORT_EMAIL_ADDRESS)), //to address, our support email address supportMessage //Email body defined above ); //Send it off amazonSimpleEmailService.sendEmail(supportEmailRequest); }

要試用它,請創建一個測試類並註入 SupportBean。 確保 SupportBeanSesImpl 中定義的 SUPPORT_EMAIL_ADDRESS 指向您擁有的電子郵件地址。 如果您的 SES 帳戶被沙盒化,則此地址也需要驗證。 可以在電子郵件地址部分下的 SES 控制台中驗證電子郵件地址。

 @Test public void emailSupport() throws JsonProcessingException { supportBean.messageSupport(1, "Hello World!"); }

運行此程序後,您應該會在收件箱中看到一條消息。 更好的是,回复消息並檢查我們之前設置的 SQS 隊列。 您應該會看到一個包含您的回复的有效負載。

使用 SQS 的回复

最後一步是讀取來自 SQS 的電子郵件,解析電子郵件消息,並確定應轉發的回复屬於哪個用戶 ID。

像 Amazon SQS 這樣的消息隊列服務在面向服務的架構中發揮著至關重要的作用,它允許服務相互通信,而不必犧牲速度、可靠性或可擴展性。

為了偵聽新的 SQS 消息,我們將使用 Spring Cloud AWS 消息傳遞 SDK。 這將允許我們通過註釋配置 SQS 消息偵聽器,從而避免大量樣板代碼。

首先,所需的依賴項。

添加 Spring Cloud 消息傳遞依賴項:

 <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-aws-messaging</artifactId> </dependency>

並將 Spring Cloud AWS 添加到您的 pom 依賴管理中:

 <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-aws</artifactId> <version>1.1.0.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>

目前,Spring Cloud AWS 不支持註解驅動配置,所以我們將不得不定義一個 XML bean。 幸運的是,我們根本不需要太多配置,所以我們的 bean 定義會很輕鬆。 該文件的主要目的是啟用註釋驅動的隊列偵聽器,這將允許我們將方法註釋為 SqsListener。

在資源文件夾中創建一個名為 aws-config.xml 的新 XML 文件。 我們的定義應該是這樣的:

 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aws-context="http://www.springframework.org/schema/cloud/aws/context" xmlns:aws-messaging="http://www.springframework.org/schema/cloud/aws/messaging" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/cloud/aws/context http://www.springframework.org/schema/cloud/aws/context/spring-cloud-aws-context.xsd http://www.springframework.org/schema/cloud/aws/messaging http://www.springframework.org/schema/cloud/aws/messaging/spring-cloud-aws-messaging.xsd"> <!--enable annotation driven queue listeners --> <aws-messaging:annotation-driven-queue-listener /> <!--define our region, this lets us reference queues by name instead of by URL. --> <aws-context:context-region region="us-east-1" /> </beans>

該文件的重要部分是<aws-messaging:annotation-driven-queue-listener /> 。 我們還定義了一個默認區域。 這不是必需的,但這樣做將允許我們通過名稱而不是 URL 來引用我們的 SQS 隊列。 我們沒有定義任何 AWS 憑證,通過省略它們,Spring 將默認為 DefaultAWSCredentialsProviderChain,這與我們之前在 SES bean 中使用的提供者相同。 更多信息可以在 Spring Cloud AWS 文檔中找到。

要在我們的 Spring Boot 應用程序中使用這個 XML 配置,我們需要顯式地導入它。 轉到您的 @SpringBootApplication 類並導入它。

 @SpringBootApplication @ImportResource("classpath:aws-config.xml") //Explicit import for our AWS XML bean definition public class EmailProcessorApplication { public static void main(String[] args) { SpringApplication.run(EmailProcessorApplication.class, args); } }

現在讓我們定義一個處理傳入 SQS 消息的 bean。 Spring Cloud AWS 讓我們通過一個註解來完成這個任務!

 /** * Bean reasonable for polling SQS and processing new emails */ @Component public class EmailSqsListener { @SuppressWarnings("unused") //IntelliJ isn't quite smart enough to recognize methods marked with @SqsListener yet @SqsListener(value = "com-example-ses", deletionPolicy = SqsMessageDeletionPolicy.ON_SUCCESS) //Mark this method as a SQS listener //Since we already set up our region we can use the logical queue name here //Spring will automatically delete messages if this method executes successfully public void consumeSqsMessage(@Headers Map<String, String> headers, //Map of headers returned when requesting a message from SQS //This map will include things like the relieved time, count and message ID @NotificationMessage String rawJsonMessage //JSON string representation of our payload //Spring Cloud AWS supports marshaling here as well //For the sake of simplicity we will work with incoming messages as a JSON object ) throws Exception{ //com.amazonaws.util.json.JSONObject included with the AWS SDK JSONObject jsonSqsMessage = new JSONObject(rawJsonMessage); } }

這裡的魔力在於@SqsListener 註釋。 有了這個,Spring 將設置一個 Executor 並開始為我們輪詢 SQS。 每次找到新消息時,都會使用消息內容調用我們的註解方法。 或者,可以將 Spring Cloud 配置為編組傳入消息,使您能夠在隊列偵聽器中使用強類型對象。 此外,您可以注入單個標頭或從底層 AWS 調用返回的所有標頭的映射。

我們可以在此處使用邏輯隊列名稱,因為我們之前在 aws-config.xml 中定義了該區域,如果我們想省略我們將能夠用我們完全限定的 SQS URL 替換該值。 我們還定義了一個刪除策略,這將配置 Spring 在滿足條件時刪除來自 SQS 的傳入消息。 SqsMessageDeletionPolicy 中定義了多個策略,如果我們的 consumeSqsMessage 方法成功執行,我們正在配置 Spring 以刪除我們的消息。

我們還使用 @Headers 將返回的 SQS 標頭注入到我們的方法中,注入的映射將包含與接收到的隊列和有效負載相關的元數據。 消息體是使用@NotificationMessage 注入的。 Spring 支持使用 Jackson 或通過自定義消息正文轉換器進行編組。 為方便起見,我們將注入原始 JSON 字符串並使用 AWS 開發工具包中包含的 JSONObject 類對其進行處理。

從 SQS 檢索到的有效負載將包含大量數據。 查看 JSONObject 以熟悉返回的有效負載。 我們的有效負載包含來自它通過的每個 AWS 服務、SES、SNS 以及最後是 SQS 的數據。 就本教程而言,我們實際上只關心兩件事:發送到的電子郵件地址列表和電子郵件正文。 讓我們從解析電子郵件開始。

 //Pull out the array containing all email addresses this was sent to JSONArray emailAddressArray = jsonSqsMessage.getJSONObject("mail").getJSONArray("destination"); for(int i = 0 ; i < emailAddressArray.length() ; i++){ String emailAddress = emailAddressArray.getString(i); }

由於在現實世界中,我們的幫助台在其回復中可能不僅僅包含原始發件人,因此我們需要在解析用戶 ID 之前驗證地址。 這將使我們的支持台能夠同時向多個用戶發送消息,以及包括非應用用戶的能力。

讓我們回到我們的 UserEmailBean 接口並添加另一個方法。

 /** * Returns true if the input email address matches our template * @param emailAddress Email to check * @return true if it matches */ boolean emailMatchesUserFormat(String emailAddress);

在 UserEmailBeanJSONImpl 中,為了實現這個方法,我們要做兩件事。 首先,檢查地址是否以我們的 EMAIL_DOMAIN 結尾,然後檢查我們是否可以編組它。

 @Override public boolean emailMatchesUserFormat(String emailAddress) { //not our address, return right away if(!emailAddress.endsWith("@" + EMAIL_DOMAIN)){ return false; } //We just care about the email part, not the domain part String emailPart = splitEmail(emailAddress); try { //Attempt to decode our email UserDetails userDetails = objectMapper.readValue(Base64.getDecoder().decode(emailPart), UserDetails.class); //We assume this email matches if the address is successfully decoded and marshaled return userDetails != null && userDetails.getUserID() != null; } catch (IllegalArgumentException | IOException e) { //The Base64 decoder will throw an IllegalArgumentException it the input string is not Base64 formatted //Jackson will throw an IOException if it can't read the string into the UserDetails class return false; } } /** * Splits an email address on @ * Returns everything before the @ * @param emailAddress Address to split * @return all parts before @. If no @ is found, the entire address will be returned */ private static String splitEmail(String emailAddress){ if(!emailAddress.contains("@")){ return emailAddress; } return emailAddress.substring(0, emailAddress.indexOf("@")); }

我們定義了兩個新方法,剛剛添加到界面中的 emailMatchesUserFormat,以及用於在 @ 上拆分電子郵件地址的簡單實用方法。 我們的 emailMatchesUserFormat 實現通過嘗試 Base64 解碼並將地址部分編組回我們的 UserDetails 幫助器類來工作。 如果成功,我們將檢查以確保填充了所需的用戶 ID。 如果一切順利,我們可以放心地假設匹配。

回到我們的 EmailSqsListener 並註入新更新的 UserEmailBean。

 private final UserEmailBean userEmailBean; @Autowired public EmailSqsListener(UserEmailBean userEmailBean) { this.userEmailBean = userEmailBean; }

現在我們要更新consumeSqsMethod。 首先讓我們解析出電子郵件正文:

 //Pull our content, remember the content will be Base64 encoded as per our SES settings String encodedContent = jsonSqsMessage.getString("content"); //Create a new String after decoding our body String decodedBody = new String( Base64.getDecoder().decode(encodedContent.getBytes()) ); for(int i = 0 ; i < emailAddressArray.length() ; i++){ String emailAddress = emailAddressArray.getString(i); }

現在讓我們創建一個新方法來處理電子郵件地址和電子郵件正文。

 private void processEmail(String emailAddress, String emailBody){ }

最後,更新電子郵件循環以在找到匹配項時調用此方法。

 //Loop over all sent to addresses for(int i = 0 ; i < emailAddressArray.length() ; i++){ String emailAddress = emailAddressArray.getString(i); //If we find a match, process the email and method if(userEmailBean.emailMatchesUserFormat(emailAddress)){ processEmail(emailAddress, decodedBody); } }

在我們實現 processEmail 之前,我們需要向我們的 UserEmailBean 添加一個方法。 我們需要一種從電子郵件中返回用戶 ID 的方法。 返回到 UserEmailBean 接口以添加其最後一個方法。

 /** * Returns the userID from a formatted email address. * Returns null if no userID is found. * @param emailAddress Formatted email address, this address should be verified using {@link #emailMatchesUserFormat(String)} * @return The originating userID if found, null if not */ Long userIDFromEmail(String emailAddress);

此方法的目標是從格式化的地址返回用戶 ID。 實現將類似於我們的驗證方法。 讓我們轉到 UserEmailBeanJSONImpl 並填寫此方法。

 @Override public Long userIDFromEmail(String emailAddress) { String emailPart = splitEmail(emailAddress); try { //Attempt to decode our email UserDetails userDetails = objectMapper.readValue(Base64.getDecoder().decode(emailPart), UserDetails.class); if(userDetails == null || userDetails.getUserID() == null){ //We couldn't find a userID return null; } //ID found, return it return userDetails.getUserID(); } catch (IllegalArgumentException | IOException e) { //The Base64 decoder will throw an IllegalArgumentException it the input string is not Base64 formatted //Jackson will throw an IOException if it can't read the string into the UserDetails class //Return null since we didn't find a userID return null; } }

現在回到我們的 EmailSqsListener 並更新 processEmail 以使用這個新方法。

 private void processEmail(String emailAddress, String emailBody){ //Parse out the email address Long userID = userEmailBean.userIDFromEmail(emailAddress); if(userID == null){ //Whoops, we couldn't find a userID. Abort! return; } }

偉大的! 現在我們幾乎擁有了我們需要的一切。 我們需要做的最後一件事是從原始消息中解析出回复。

電子郵件客戶端,就像幾年前的網絡瀏覽器一樣,受到其實現不一致的困擾。

解析電子郵件中的回复實際上是一項相當複雜的任務。 電子郵件消息格式未標準化,不同電子郵件客戶端之間的差異可能很大。 原始響應也將包括比回復和簽名更多的內容。 原始消息很可能也會包含在內。 Mailgun 的聰明人整理了一篇很棒的博客文章,解釋了一些挑戰。 他們還開源了基於機器學習的電子郵件解析方法,在這裡查看。

Mailgun 庫是用 Python 編寫的,因此在我們的教程中,我們將使用更簡單的基於 Java 的解決方案。 GitHub 用戶 edlio 基於 GitHub 的一個庫,用 Java 編寫了一個 MIT 許可的電子郵件解析器。 我們將使用這個很棒的庫。

首先讓我們更新我們的 pom,我們將使用 https://jitpack.io 來拉入 EmailReplyParser。

 <repositories> <repository> <id>jitpack.io</id> <url>https://jitpack.io</url> </repository> </repositories>

現在添加 GitHub 依賴項。

 <dependency> <groupId>com.github.edlio</groupId> <artifactId>EmailReplyParser</artifactId> <version>v1.0</version> </dependency>

我們還將使用 Apache 公共電子郵件。 在將原始電子郵件傳遞給 EmailReplyParser 之前,我們需要將原始電子郵件解析為 javax.mail MimeMessage。 添加公共依賴項。

 <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-email</artifactId> <version>1.4</version> </dependency>

現在我們可以回到我們的 EmailSqsListener 並完成 processEmail。 此時,我們有了原始用戶 ID 和原始電子郵件正文。 剩下要做的就是解析出回复。

為此,我們將結合使用 javax.mail 和 edlio 的 EmailReplyParser。

 private void processEmail(String emailAddress, String emailBody) throws Exception { //Parse out the email address Long userID = userEmailBean.userIDFromEmail(emailAddress); if(userID == null){ //Whoops, we couldn't find a userID. Abort! return; } //Default javax.mail session Session session = Session.getDefaultInstance(new Properties()); //Create a new mimeMessage out of the raw email body MimeMessage mimeMessage = MimeMessageUtils.createMimeMessage( session, emailBody ); MimeMessageParser mimeMessageParser = new MimeMessageParser(mimeMessage); //Parse the message mimeMessageParser.parse(); //Parse out the reply for our message String replyText = EmailReplyParser.parseReply(mimeMessageParser.getPlainContent()); //Now we're done! //We have both the userID and the response! System.out.println("Processed reply for userID: " + userID + ". Reply: " + replyText); }

包起來

就是這樣! 我們現在擁有向原始用戶提供響應所需的一切!

看? 我告訴過你電子郵件可以很有趣!

在本文中,我們了解瞭如何使用 Amazon Web Services 來編排複雜的管道。 儘管在本文中,管道是圍繞電子郵件設計的; 這些相同的工具可用於設計更複雜的系統,您不必擔心維護基礎設施,而可以專注於軟件工程的有趣方面。

相關:使用 Amazon Web Services 提高您的工作效率