Лямбда-приложение Micronaut GraalVM Sendgrid AWS продолжает получать сообщение 400 от Sendgrid при попытке отправить элеJAVA

Программисты JAVA общаются здесь
Ответить Пред. темаСлед. тема
Anonymous
 Лямбда-приложение Micronaut GraalVM Sendgrid AWS продолжает получать сообщение 400 от Sendgrid при попытке отправить эле

Сообщение Anonymous »

Я создал простое приложение для электронной почты, используя micronaut, java и sendgrid. Использование его в качестве базового Java-приложения, развернутого на AWS, работает, электронные письма отправляются
нормально. Я создал еще одну лямбду, чтобы попробовать использовать возможности GraalVM. Я просто следовал руководству документации Micronaut, все компилируется и собирается
с использованием ./gradlew buildNativeLambda. Запуск опции тестирования в консоли AWS работает, и приложение не возвращает ошибок, однако sendgrid отправляет
обратно 400. Я чувствую, что мне не хватает чего-то основного. Я попробовал добавить все, что мог придумать, в
resources/META-INF/native-image/reflect-config.json . Пробовал разные способы, показанные в документации micronaut, для запуска лямбды, т. е. с помощью метода Controller
, FunctionRequestHandler и FunctionLambdaRuntime. С каждым из них лямбда будет работать и возвращает строку или APIGatewayProxyResponseEvent
без проблем. Кажется, что-то есть с созданием электронной почты, и я чувствую, что на этом этапе я просто швырялся в стену, и ничего
не прилипает, независимо от того, что я меняю, я не получаю новых кодов ошибок или чего-то еще подтолкните меня в правильном направлении.
  • Текущий build.gradle – на данный момент он очень раздут, но, как я уже сказал, я застрял в попытках получить это работает, поэтому я, похоже, просто продолжаю
    добавлять что-то в надежде, что что-то изменится

Код: Выделить всё

    plugins {
id("com.github.johnrengelman.shadow") version "8.1.1"
id("io.micronaut.application") version "4.4.2"
id("com.diffplug.spotless") version "6.23.3"
id("io.micronaut.aot") version "4.4.2"
}

version = "0.1"
group = "example.micronaut"

repositories {
mavenCentral()
}

dependencies {
annotationProcessor("io.micronaut:micronaut-http-validation")
annotationProcessor("io.micronaut.serde:micronaut-serde-processor")
implementation("io.micronaut.email:micronaut-email-sendgrid")
implementation("io.micronaut:micronaut-http-client-jdk")
implementation("jakarta.mail:jakarta.mail-api:2.1.3")
implementation("io.micronaut.aws:micronaut-aws-lambda-events-serde")
implementation("io.micronaut.serde:micronaut-serde-jackson")
runtimeOnly("org.yaml:snakeyaml")
runtimeOnly("ch.qos.logback:logback-classic")
}

application {
mainClass = "example.micronaut.Application"
}
java {
sourceCompatibility = JavaVersion.toVersion("17")
targetCompatibility = JavaVersion.toVersion("17")
}

shadowJar {
// Ensure resources are included
mergeServiceFiles()
include 'EmailTemplate/**'
}

sourceSets {
main {
resources {
srcDirs = ['src/main/resources']
//            include([ '**/*.properties', '**/*.yml', '**/*.json', '**/*.png', '**/*.html',  '**/*.css','**/*.JPG'])
}
}
}

graalvmNative {
toolchainDetection = false

binaries {
main {
javaLauncher = javaToolchains.launcherFor {
languageVersion = JavaLanguageVersion.of(17)
vendor = JvmVendorSpec.matching("GraalVM Community")
}
resources.autodetect()
metadataRepository { enabled = true }
imageName.set('graal-mail')
buildArgs.add('--verbose')
buildArgs.add('--initialize-at-build-time=kotlin.coroutines.intrinsics.CoroutineSingletons')
buildArgs.add('--initialize-at-run-time=reactor.core.publisher.Traces$StackWalkerCallSiteSupplierFactory')
buildArgs.add('--initialize-at-run-time=reactor.core.publisher.Traces$ExceptionCallSiteSupplierFactory')
}
}
}

micronaut {
runtime("lambda_provided")
testRuntime("junit5")
processing {
incremental(true)
annotations("example.micronaut.*")
}
aot {
// Please review carefully the optimizations enabled below
// Check https://micronaut-projects.github.io/micronaut-aot/latest/guide/ for more details
optimizeServiceLoading = false
convertYamlToJava = false
precomputeOperations = true
cacheEnvironment = true
optimizeClassLoading = true
deduceEnvironment = true
optimizeNetty = true
replaceLogbackXml = true
}
}

tasks.named("dockerfileNative") {
baseImage = "amazonlinux:2023"
jdkVersion = "17"
args(
"-XX:MaximumHeapSizePercent=80",
"-Dio.netty.allocator.numDirectArenas=0",
"-Dio.netty.noPreferDirect=true"
)
}

spotless {
java {
licenseHeaderFile(file("LICENSEHEADER"))
}
}
  • Конструктор электронной почты — снова на этом этапе я добавляю аннотации к вещам там, где они, вероятно, не нужны, но, кажется, ничто на это не влияет, приложение работает, но из лямбда-версии GraalVM электронные письма отправляются неправильно

Код: Выделить всё

    package example.micronaut.services

import com.sendgrid.Response;
import example.micronaut.Util.MimeType;
import example.micronaut.Util.UtilMailService;
import io.micronaut.context.annotation.Value;
import io.micronaut.core.annotation.ReflectiveAccess;
import io.micronaut.email.BodyType;
import io.micronaut.email.Email;
import io.micronaut.email.sendgrid.SendgridEmailSender;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import jakarta.mail.internet.MimeBodyPart;

import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;

@Singleton
@ReflectiveAccess
public class TestCampaign {
private final UtilMailService utilMailService;
private final SendgridEmailSender sendgridEmailSender;

@Value("${micronaut.email.from.email}")
private String fromEmail;

@Inject
public TestCampaign(SendgridEmailSender sendgridEmailSender, UtilMailService utilMailService) {
this.sendgridEmailSender = sendgridEmailSender;
this.utilMailService = utilMailService;
}

public Response sendTestEmail() throws Exception {
AtomicInteger index = new AtomicInteger(0);
Email.Builder emailBuilder = getEmailBuilder();

utilMailService.getContacts("EmailTemplate/EmailListTest.json").forEach(contact -> {
if (index.getAndIncrement() == 0) {
emailBuilder.to(contact);
} else {
emailBuilder.bcc(contact);
}
});

return sendgridEmailSender.send(emailBuilder.build());
}

private Email.Builder getEmailBuilder() throws Exception {
Optional  bodyOption = utilMailService.readHtmlFile("EmailTemplate/StdEmail.html");
String body = bodyOption.orElse("Be Aware of Your Prescriptions at work");
return Email.builder()
.from(fromEmail)
.subject("subject")
.body(body, BodyType.HTML)
.attachment(utilMailService.buildAttachment("EmailTemplate/Meds1.png", "meds1.png", MimeBodyPart.ATTACHMENT, MimeType.IMAGE_PNG).build())
.attachment(utilMailService.buildAttachment("EmailTemplate/Meds2.png", "meds2.png", MimeBodyPart.ATTACHMENT, MimeType.IMAGE_PNG).build())
.attachment(utilMailService.buildAttachment("EmailTemplate/Meds3.JPG", "meds3.JPG", MimeBodyPart.ATTACHMENT, MimeType.IMAGE_JPEG).build())
.attachment(utilMailService.buildAttachment("EmailTemplate/AllMeds.png", "AllMeds.png", MimeBodyPart
  • Текущая утилита, добавляющая контакты из файла JSON, вложений и HTML-страницы из ресурсов.

Код: Выделить всё

    package example.micronaut.Util;

import io.micronaut.core.annotation.NonNull;
import io.micronaut.core.annotation.Nullable;
import io.micronaut.core.annotation.ReflectiveAccess;
import io.micronaut.core.io.IOUtils;
import io.micronaut.core.io.ResourceResolver;
import io.micronaut.core.type.Argument;
import io.micronaut.email.Attachment;
import io.micronaut.email.Contact;
import io.micronaut.serde.ObjectMapper;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import jakarta.mail.internet.MimeBodyPart;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.*;

@Singleton
@ReflectiveAccess
public class UtilMailService {
private final ResourceResolver resourceResolver;
private final ObjectMapper objectMapper;

@Inject
public UtilMailService(ResourceResolver resourceResolver, ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
this.resourceResolver = resourceResolver;
}

public @NonNull Attachment.Builder buildAttachment(String path, String name, String disposition, MimeType type) throws Exception {
Optional fileBytes = getClasspathResourceAsBytes(path);

if (fileBytes.isEmpty()) {
throw new IllegalArgumentException("File not found! " + path);
}

Attachment.Builder newAttachment = Attachment.builder().filename(name).contentType(type.getMimeType()).content(fileBytes.get());

if (Objects.equals(disposition, MimeBodyPart.INLINE)) {

newAttachment.id(name).disposition(disposition);
}

return newAttachment;
}

public Optional getClasspathResourceAsBytes(String path) throws Exception {
Optional url = resourceResolver.getResource("classpath:" + path);
if (url.isPresent()) {
try (InputStream inputStream = url.get().openStream()) {
return Optional.of(inputStream.readAllBytes());
}
}
else {
return Optional.empty();
}
}

public List getContacts(String path) throws IOException {
List contactList = new ArrayList();
Map contactMap = readJsonFileToMap(path).orElse(Map.of("[email protected]", "crash"));
contactMap.forEach((key, value) -> {
contactList.add(new Contact(key, value));
});

return contactList;
}

public @Nullable Optional readJsonFileToMap(String resourcePath) throws IOException {
Optional url = resourceResolver.getResource("classpath:"  + resourcePath);
if (url.isPresent()) {
try (InputStream inputStream = url.get().openStream()) {
return Optional.of(objectMapper.readValue(inputStream.readAllBytes(), Argument.mapOf(String.class, String.class)));
}
}
else {
return Optional.empty();
}
}

public Optional readHtmlFile(String path) throws Exception {
Optional url = resourceResolver.getResource("classpath:" + path);
if (url.isPresent()) {
return Optional.of(IOUtils.readText(new BufferedReader(new InputStreamReader(url.get().openStream()))));
}
else {
return Optional.empty();
}
}

public Optional getClasspathResourceAsText(String path) throws Exception {
Optional url = resourceResolver.getResource("classpath:" + path);
if (url.isPresent()) {
return Optional.of(IOUtils.readText(new BufferedReader(new InputStreamReader(url.get().openStream()))));
}
else {
return Optional.empty();
}
}
}
  • Код контроллера

Код: Выделить всё

package example.micronaut;

import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent;
import com.sendgrid.Response;
import example.micronaut.services.EmailSendingService;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;
import io.micronaut.http.annotation.QueryValue;
import io.micronaut.serde.ObjectMapper;
import jakarta.inject.Inject;

import java.util.Collections;

@Controller
public class HomeController {
private final EmailSendingService emailSendingService;
@Inject
ObjectMapper objectMapper;
APIGatewayProxyResponseEvent response = new APIGatewayProxyResponseEvent();

@Inject
public HomeController(EmailSendingService emailSendingService) {
this.emailSendingService = emailSendingService;
}

@Get
public APIGatewayProxyResponseEvent index(@QueryValue(defaultValue = "test") String campaign) {
try {

Response sendGridResponse = emailSendingService.sendCustomizedEmail(campaign);
String json = new String(objectMapper.writeValueAsBytes(Collections.singletonMap("message", response.getHeaders())));
response.setStatusCode(sendGridResponse.getStatusCode());
response.setBody(json);
}
catch (Exception e) {
response.setStatusCode(500);
response.setBody(String.valueOf(e.getMessage()));
}

return response;
}
}
  • текущая конфигурация времени выполнения
Изображение

[*]тестовый ответ

-- журнал выполнения

Код: Выделить всё

    {
"statusCode": 200,
"headers": {
"Date": "Sat, 14 Sep 2024 18:05:23 GMT",
"Content-Type": "application/json"
},
"multiValueHeaders": {
"Date": [
"Sat, 14 Sep 2024 18:05:23 GMT"
],
"Content-Type": [
"application/json"
]
},
"body": "{\"statusCode\":400,\"body\":\"{\\\"message\\\":null}\"}",
"isBase64Encoded": false
}
-- вывод журнала

Код: Выделить всё

    START RequestId: b984c570-f7af-4d4c-a929-0ae8cf1fdcd7 Version: $LATEST
[36m18:05:23.612 [0;39m  [1;30m[main] [0;39m  [34mINFO  [0;39m  [35mi.m.e.sendgrid.SendgridEmailSender [0;39m - Status Code: 400
[36m18:05:23.612 [0;39m  [1;30m[main] [0;39m  [34mINFO  [0;39m  [35mi.m.e.sendgrid.SendgridEmailSender [0;39m - Body: {"errors":[{"message":"The from object must be provided for every email send. It is an object that requires the email parameter, but may also contain a name parameter.  e.g.  {\"email\" : \"[email protected]\"}  or {\"email\" : \"[email protected]\", \"name\" : \"Example Recipient\"}.","field":"from.email","help":"http://sendgrid.com/docs/API_Reference/Web_API_v3/Mail/errors.html#message.from"},{"message":"The personalizations field is required and must have at least one personalization.","field":"personalizations","help":"http://sendgrid.com/docs/API_Reference/Web_API_v3/Mail/errors.html#-Personalizations-Errors"},{"message":"Unless a valid template_id is provided, the content parameter is required. There must be at least one defined content block. We typically suggest both text/plain and text/html blocks are included, but only one block is required.","field":"content","help":"http://sendgrid.com/docs/API_Reference/Web_API_v3/Mail/errors.html#message.content"}]}
[36m18:05:23.612 [0;39m  [1;30m[main] [0;39m  [34mINFO  [0;39m  [35mi.m.e.sendgrid.SendgridEmailSender [0;39m - Headers {Strict-Transport-Security=max-age=600; includeSubDomains, Server=nginx, Access-Control-Allow-Origin=https://sendgrid.api-docs.io, Access-Control-Allow-Methods=POST, Connection=keep-alive, X-No-CORS-Reason=https://sendgrid.com/docs/Classroom/Basics/API/cors.html, Content-Length=980, Access-Control-Max-Age=600, Date=Sat, 14 Sep 2024 18:05:23 GMT, Access-Control-Allow-Headers=Authorization, Content-Type, On-behalf-of, x-sg-elas-acl, Content-Type=application/json}
END RequestId: b984c570-f7af-4d4c-a929-0ae8cf1fdcd7
REPORT RequestId: b984c570-f7af-4d4c-a929-0ae8cf1fdcd7  Duration: 2722.27 ms    Billed Duration: 2723 ms    Memory Size: 128 MB Max Memory Used: 113 MB
Как я уже сказал, приложение работает, если оно не развернуто как GraalVM. Мы будем очень признательны за любую помощь или что-то еще.
Я попробовал добавить все, что мог придумать, в resources/META-INF/native-image/reflect-config.json . Пробовал различные способы, показанные в документации
micronaut, для запуска лямбда-выражения, т. е. с использованием метода контроллера, FunctionRequestHandler и FunctionLambdaRuntime. С каждым из них лямбда
работает и без проблем возвращает строку или APIGatewayProxyResponseEvent. Кажется, что-то есть с созданием электронной почты

Подробнее здесь: https://stackoverflow.com/questions/789 ... returned-f
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «JAVA»