GET
/
api
/
v2
/
attachments
/
{id}
/
{filename}
import { NextRequest, NextResponse } from 'next/server'
import type { InboundWebhookPayload } from '@inboundemail/sdk'

export async function POST(request: NextRequest) {
  const payload: InboundWebhookPayload = await request.json()
  const { email } = payload
  
  // Download first attachment
  if (email.parsedData.attachments.length > 0) {
    const attachment = email.parsedData.attachments[0]
    
    const response = await fetch(attachment.downloadUrl, {
      headers: {
        'Authorization': `Bearer ${process.env.INBOUND_API_KEY}`
      }
    })
    
    if (response.ok) {
      const fileBuffer = await response.arrayBuffer()
      console.log(`Downloaded ${attachment.filename}: ${fileBuffer.byteLength} bytes`)
      
      // Save to disk, cloud storage, etc.
      await saveFile(attachment.filename, fileBuffer)
    }
  }
  
  return NextResponse.json({ success: true })
}
{
  "error": "Email not found or access denied"
}

Overview

This endpoint allows you to download email attachments using the email ID and filename. The attachment URL is automatically provided in webhook payloads for easy access.
This endpoint is typically used with the downloadUrl field provided in webhook payloads, but you can also construct the URL manually if needed.

Authentication

Authorization
string
required
Bearer token for API authentication. Format: Bearer YOUR_API_KEY

Path Parameters

id
string
required
The structured email ID (the email’s unique identifier in Inbound).
filename
string
required
The filename of the attachment to download. Must be URL-encoded if it contains special characters.

Response

The endpoint returns the raw file content with appropriate headers:
  • Content-Type: The attachment’s MIME type (e.g., application/pdf, image/png)
  • Content-Disposition: Set to attachment; filename="..." for proper download behavior
  • Content-Length: Size of the file in bytes
  • Cache-Control: Set to private, max-age=3600 for secure caching

Examples

Download from Webhook Payload

import { NextRequest, NextResponse } from 'next/server'
import type { InboundWebhookPayload } from '@inboundemail/sdk'

export async function POST(request: NextRequest) {
  const payload: InboundWebhookPayload = await request.json()
  const { email } = payload
  
  // Download first attachment
  if (email.parsedData.attachments.length > 0) {
    const attachment = email.parsedData.attachments[0]
    
    const response = await fetch(attachment.downloadUrl, {
      headers: {
        'Authorization': `Bearer ${process.env.INBOUND_API_KEY}`
      }
    })
    
    if (response.ok) {
      const fileBuffer = await response.arrayBuffer()
      console.log(`Downloaded ${attachment.filename}: ${fileBuffer.byteLength} bytes`)
      
      // Save to disk, cloud storage, etc.
      await saveFile(attachment.filename, fileBuffer)
    }
  }
  
  return NextResponse.json({ success: true })
}

Save to Cloud Storage

import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3'
import type { InboundWebhookPayload } from '@inboundemail/sdk'

const s3Client = new S3Client({ region: 'us-east-1' })

export async function POST(request: NextRequest) {
  const payload: InboundWebhookPayload = await request.json()
  const { email } = payload
  
  // Download and upload attachments to S3
  for (const attachment of email.parsedData.attachments) {
    // Download from Inbound
    const response = await fetch(attachment.downloadUrl, {
      headers: {
        'Authorization': `Bearer ${process.env.INBOUND_API_KEY}`
      }
    })
    
    if (response.ok) {
      const fileBuffer = await response.arrayBuffer()
      
      // Upload to S3
      await s3Client.send(new PutObjectCommand({
        Bucket: 'my-email-attachments',
        Key: `emails/${email.id}/${attachment.filename}`,
        Body: Buffer.from(fileBuffer),
        ContentType: attachment.contentType
      }))
      
      console.log(`Uploaded ${attachment.filename} to S3`)
    }
  }
  
  return NextResponse.json({ success: true })
}

Error Responses

{
  "error": "Email not found or access denied"
}

Important Notes

Authentication Required: You must include a valid API key in the Authorization header to download attachments. Only the email owner can download attachments.
Smart Content Retrieval: The endpoint automatically tries S3 storage first, then falls back to direct email content if S3 is unavailable.
URL Encoding: If the filename contains special characters, it should be URL-encoded in the download URL. The downloadUrl in webhook payloads is already properly encoded.

Usage in Webhook Handlers

The most common use case is downloading attachments from webhook payloads:
import { InboundWebhookPayload } from '@inboundemail/sdk'

export async function POST(request: Request) {
  const payload: InboundWebhookPayload = await request.json()
  const { email } = payload
  
  console.log(`Email has ${email.parsedData.attachments.length} attachments`)
  
  for (const attachment of email.parsedData.attachments) {
    // The downloadUrl is ready to use
    console.log(`Download: ${attachment.downloadUrl}`)
    
    // Fetch the file
    const file = await fetch(attachment.downloadUrl, {
      headers: {
        'Authorization': `Bearer ${process.env.INBOUND_API_KEY}`
      }
    })
    
    if (file.ok) {
      // Process the file
      const data = await file.arrayBuffer()
      await processAttachment(attachment.filename, data)
    }
  }
  
  return new Response('OK')
}

Security Considerations

1

API Key Protection

Never expose your API key in client-side code. Always download attachments from server-side code.
2

User Verification

The endpoint automatically verifies that the requesting user owns the email before allowing downloads.
3

Content Type Validation

Always validate the content type before processing downloaded files to prevent security issues.

Notes

  • Attachments are downloaded as raw binary data
  • The endpoint respects S3 storage location and falls back to direct content
  • Only the email owner (authenticated user) can download attachments
  • The filename in the URL is used for proper Content-Disposition headers
  • Large attachments may take longer to download depending on size
  • Download URLs in webhook payloads are automatically URL-encoded

1.0 - ✅