You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Serverless Node.js中REST API转Multipart文件为邮件附件的实现咨询

Improved Implementation for Your File-to-Email REST API

Your core idea is solid, but the current code misses critical functionality (handling multipart/form-data, processing the uploaded file, and validating the PATCH method) and has some areas where we can boost security, readability, and robustness. Here's a refined approach:

Key Improvements & Fixes

1. Parse Multipart/Form-Data Requests

Lambda's event payload doesn't automatically parse multipart data—you'll need a helper library to extract the uploaded file. lambda-multipart-parser is a great fit for this use case (it's lightweight and designed specifically for Lambda).

2. Secure Configuration with Environment Variables

Never hardcode credentials in your code! Store SMTP credentials, hosts, and ports as Lambda environment variables—this keeps sensitive data safe and makes configuration changes easier without redeploying code.

3. Use Async/Await Instead of Callbacks

Callback-based code can get messy quickly. Switching to async/await makes your code more readable and simplifies error handling.

4. Validate Request Method & Input

Ensure the request uses the PATCH method, and check that a file was actually uploaded before attempting to send the email.

5. Properly Attach the Uploaded File to the Email

Once you extract the file from the request, add it to Nodemailer's attachments array with the correct metadata (filename, content type, and content).

Refactored Code Example

First, install the required dependencies:

npm install nodemailer lambda-multipart-parser

Then update your code:

const nodemailer = require('nodemailer');
const multipartParser = require('lambda-multipart-parser');

// Pull config from Lambda environment variables
const config = {
  smtp: {
    host: process.env.SMTP_HOST,
    port: parseInt(process.env.SMTP_PORT, 10),
    username: process.env.SMTP_USERNAME,
    password: process.env.SMTP_PASSWORD
  },
  email: {
    from: process.env.EMAIL_FROM || 'wat@address.com',
    to: process.env.EMAIL_TO || 'inbox@address.com'
  }
};

// Reuse transporter across invocations (helps with Lambda cold starts)
let transporter;
const getTransporter = () => {
  if (!transporter) {
    transporter = nodemailer.createTransport({
      host: config.smtp.host,
      port: config.smtp.port,
      secure: config.smtp.port === 465, // Auto-enable secure for port 465
      auth: {
        user: config.smtp.username,
        pass: config.smtp.password
      }
    });
  }
  return transporter;
};

module.exports.endpoint = async (event) => {
  try {
    // Validate request method
    if (event.httpMethod !== 'PATCH') {
      return {
        statusCode: 405,
        headers: { 'Access-Control-Allow-Origin': process.env.CORS_ORIGIN || '*' },
        body: JSON.stringify({ error: 'Method Not Allowed. Use PATCH.' })
      };
    }

    // Parse multipart form data
    const parsedData = await multipartParser.parse(event);
    
    // Check if a file was uploaded
    if (!parsedData.files || parsedData.files.length === 0) {
      return {
        statusCode: 400,
        headers: { 'Access-Control-Allow-Origin': process.env.CORS_ORIGIN || '*' },
        body: JSON.stringify({ error: 'No file uploaded. Please attach a file.' })
      };
    }

    // Prepare email options with attachment
    const mailOptions = {
      from: config.email.from,
      to: config.email.to,
      subject: 'Here is a file',
      text: 'Please see attached',
      attachments: parsedData.files.map(file => ({
        filename: file.filename,
        content: file.content,
        contentType: file.contentType
      }))
    };

    // Send email
    await getTransporter().sendMail(mailOptions);

    return {
      statusCode: 202,
      headers: { 'Access-Control-Allow-Origin': process.env.CORS_ORIGIN || '*' },
      body: JSON.stringify({ message: 'Accepted. File will be sent via email.' })
    };

  } catch (error) {
    console.error('Error processing request:', error);
    return {
      statusCode: 500,
      headers: { 'Access-Control-Allow-Origin': process.env.CORS_ORIGIN || '*' },
      body: JSON.stringify({ error: `Failed to process request: ${error.message}` })
    };
  }
};

Additional Recommendations

  • Restrict CORS: Instead of using * for Access-Control-Allow-Origin, set it to specific domains (e.g., https://yourfrontend.com) to improve security.
  • File Validation: Add checks for file size (e.g., reject files larger than 10MB) and allowed file types (e.g., only PDFs, images) to prevent abuse.
  • Logging: Use structured logging (e.g., console.log(JSON.stringify({ event: 'email_sent', timestamp: new Date().toISOString() }))) to make debugging easier.
  • SMTP Connection Testing: Add a quick connection test when initializing the transporter to catch configuration errors early.

内容的提问来源于stack exchange,提问作者Matt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 13:13:11