使用 Lambda 函数通过 AWS SES Nodemailer 发送带有附件的电子邮件不一致

Sending email with attachments through AWS SES Nodemailer using Lambda function is not consistent

提问人:Paco 提问时间:11/2/2023 最后编辑:John RotensteinPaco 更新时间:11/2/2023 访问量:29

问:

发送没有附件的电子邮件效果很好,但是一旦我尝试附加文件,有时它们就会通过,有时我在调用 API 时收到错误 500,但即使发送电子邮件,它也非常不一致,但我似乎无法弄清楚为什么。

有 3 种情况:发送不带附件的电子邮件表单、发送带有 1 个 pdf 附件或 2 个 pdf 的电子邮件。

以下是Node.js代码:

const aws = require("aws-sdk");
const nodemailer = require("nodemailer");
const generateUniqueId = require("generate-unique-id");

const id = generateUniqueId({
  length: 6, 
});

exports.handler = async (event) => {
  const {
    message,
    email,
    projectName,
    fullName,
    phoneNumber,
    birthday,
    danishResidence,
    base64DataOne,
    fileNameOne,
    base64DataTwo,
    fileNameTwo,
  } = JSON.parse(event.body);


  const transporter = nodemailer.createTransport({
    SES: new aws.SES({
      region: "us-east-1",
      apiVersion: "2010-12-01",
    }),
  });

  let attachmentsFiles = [];

// Check if base64DataOne is a valid base64 string
if (base64DataOne) {
    attachmentsFiles.push({
        filename: fileNameOne,
        content: base64DataOne,
        encoding: "base64",
    });
} 

// Check if base64DataTwo is a valid base64 string
if (base64DataTwo) {
    attachmentsFiles.push({
        filename: fileNameTwo,
        content: base64DataTwo,
        encoding: "base64",
    });
} 


  let htmlTemplate = ` <div>
        <div>
            <span style="font-weight: bold">Project Name: </span> <span>${projectName}</span>
        </div>
        <div>
            <span style="font-weight: bold">Applicant Name: </span> <span>${fullName}</span>
        </div>
        <div>
            <span style="font-weight: bold">Email address: </span> <a href="mailto:${email}">${email}</a>
        </div>
        <div>
            <span style="font-weight: bold">Phone number: </span> <span>${phoneNumber}</span>
        </div>

        <div>
            <span style="font-weight: bold">Birthday: </span> <span>${birthday}</span>
        </div>
        <div>
            <span style="font-weight: bold">Valid Danish Residence: </span> <span>${danishResidence}</span>
        </div>
        
    </div>`;

  let emailProps = await transporter.sendMail({
    from: 'mail',
    to: 'mail',
    subject: "New application for a Erasmus+ project! " + "#" + id,
    text: message,
    html: htmlTemplate,
    attachments: attachmentsFiles,
  });
  return emailProps;
};

我正在使用 Nuxt 3 作为我的前端。代码如下所示:

<template>
    <form @submit.prevent="handleSubmit()">

        <div class="drag-drop cursor-pointer" :class="{ 'drag-over': isDragging }" @dragover.prevent="dragover"
            @dragleave.prevent="dragleave" @drop.prevent="drop">
            <label class="file-input-label">
                <input ref="fileInput" accept=".pdf" type="file" multiple style="display: none;" @change="onChange" />
                <p class=" cursor-pointer" v-if="!isDragging">Drag & drop files here or click to browse</p>
                <p v-else>Drop files here</p>
            </label>
            <ul v-if="files.length > 0">
                <li v-for="(file, index) in files" :key="index">
                    {{ file.file.name }} ({{ formatSize(file.file.size) }})
                    <button @click="deleteFile(index)">Delete</button>
                </li>
            </ul>
            <p v-if="fileSizeExceeded">File size exceeds the 2MB limit.</p>
            <p v-if="fileCountExceeded">Maximum of two files allowed.</p>
            <p v-if="showPDFWarning">Only PDF files are allowed</p>

        </div>
        <p v-if="loading">Loading</p>
        <p v-if="sentSuccess">Sent!</p>
        <input type="text" required> <label for=""> type the text</label>
        <button type="submit" :disabled="sentSuccess"> submit</button>
    </form>
    <!-- <button @click="handleSubmit()" :disabled="sentSuccess">Send Application</button> -->
</template>
<script setup>


const isDragging = ref(false);
const files = ref([]);
const fileSizeExceeded = ref(false);
const loading = ref(false)
const sentSuccess = ref(false)
const fileCountExceeded = ref(false);
const showPDFWarning = ref(false)


const dragover = (e) => {
    e.preventDefault();
    isDragging.value = true;
};

const dragleave = () => {
    isDragging.value = false;
};

const drop = (e) => {
    e.preventDefault();
    isDragging.value = false;
    const droppedFiles = Array.from(e.dataTransfer.files);
    validateAndAddFiles(droppedFiles);
};

const fileInput = ref(null);
let nowDate = new Date();
let date = nowDate.getFullYear() + '/' + nowDate.getDate() + '/' + (nowDate.getMonth() + 1);



const onChange = () => {
    const inputFiles = Array.from(fileInput.value.files);
    validateAndAddFiles(inputFiles);
    fileInput.value.value = ''; // Clear the input value
};

const validateAndAddFiles = async (newFiles) => {
    for (const file of newFiles) {
        if (file.type === 'application/pdf') { // Check if the file is a PDF
            if (file.size <= 2 * 1024 * 1024) {
                if (files.value.length < 2) {
                    await convertToBase64(file);
                    showPDFWarning.value = false
                    fileSizeExceeded.value = false;
                    fileCountExceeded.value = false;
                } else {
                    fileCountExceeded.value = true;
                }
            } else {
                fileSizeExceeded.value = true;
            }
        } else {
            showPDFWarning.value = true
            // Handle non-PDF files here, e.g., display an error message
            console.log(`File '${file.name}' is not a PDF and will not be added.`);
        }
    }
};
const convertToBase64 = (file) => {
    return new Promise((resolve) => {
        const reader = new FileReader();
        reader.readAsDataURL(file);
        reader.onload = () => {
            files.value.push({
                file: file,
                base64: reader.result.split(',')[1], // Get the Base64 content
            });
            resolve();
        };
    });
};


const deleteFile = (index) => {
    files.value.splice(index, 1);
};

const formatSize = (bytes) => {
    const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
    if (bytes === 0) return '0 Byte';
    const i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
    return Math.round((bytes / Math.pow(1024, i))) + ' ' + sizes[i];
};

const handleSubmit = (e) => {
    loading.value = true;

    const requestBody = {
  
        message: "This is a test email",
        email: "[email protected]",
        // date: date,
        projectName: 'projectName',
        fullName: 'name',
        phoneNumber: '123',
        birthday: '29/02/2000',
        danishResidence: 'yes'
    };

    if (files.value[0] && files.value[0].base64 && files.value[0].file.name) {
        requestBody.base64DataOne = files.value[0].base64;
        requestBody.fileNameOne = files.value[0].file.name;
    }

    if (files.value[1] && files.value[1].base64 && files.value[1].file.name) {
        requestBody.base64DataTwo = files.value[1].base64;
        requestBody.fileNameTwo = files.value[1].file.name;
    }

    fetch(
        "amazonAPI",
        {
            mode: "no-cors",
            method: "POST",
            headers: {
                Accept: "application/json",
                "Content-Type": "application/json",
            },
            body: JSON.stringify(requestBody),
        }
    )
        .then(() => {
            loading.value = false;
            sentSuccess.value = true;
            console.log("Email Sent");
        })
        .catch((err) => {
            console.log(err);
            loading.value = false;
        });
};


</script>
node.js amazon-web-services aws-lambda amazon-ses

评论


答: 暂无答案