/mail/{id}/attachment/{n}

GET

Download a specific attachment file from an email.

GET /api/mail/{id}/attachment/{n}

Description

This endpoint downloads a specific attachment file from an email. It returns the binary file content with appropriate HTTP headers including Content-Type, Content-Disposition, X-Attachment-ID, and X-Email-ID. The response Content-Type is automatically determined based on the file extension.

Binary File Response

This endpoint returns raw binary file data, not JSON. The Content-Disposition header includes the original filename to enable proper file downloads. Custom headers provide additional metadata about the attachment and email.

Interactive API Tester

Try it out

http://localhost:8080/api/mail/{id}/attachment/{n}

Path Parameters

The request requires two path parameters to identify the email and specific attachment.

Parameter Type Required Description
id string Yes The unique identifier of the email. Must be a 32-character hexadecimal string (e.g., "a1b2c3d4e5f6789012345678abcdef90").
n integer Yes The attachment ID. Must be a positive integer (e.g., 1, 2, 3). This value corresponds to the attachment_id from the attachments list endpoint.

Response

Upon success, the endpoint returns a 200 OK response with the binary file content and appropriate headers.

Response Headers

Content-Type string
The MIME type of the file, automatically determined based on the file extension (e.g., "application/pdf", "image/jpeg", "application/octet-stream").
Content-Disposition string
Instructs the browser to download the file with its original filename (e.g., "attachment; filename=\"invoice.pdf\"").
X-Attachment-ID string
The attachment ID that was downloaded.
X-Email-ID string
The email ID from which the attachment was downloaded.

Response Body

Binary File Data binary
The raw binary content of the attachment file.

Example Response Headers

HTTP/1.1 200 OK
Content-Type: application/pdf
Content-Disposition: attachment; filename="invoice.pdf"
Content-Length: 245760
X-Attachment-ID: 1
X-Email-ID: a1b2c3d4e5f6789012345678abcdef90

[Binary file data]

Common Content-Types by Extension

  • PDF: application/pdf
  • Images (JPEG, PNG, GIF): image/jpeg, image/png, image/gif
  • Documents (DOCX, XLSX): application/vnd.openxmlformats-officedocument.*
  • Text files: text/plain
  • ZIP archives: application/zip
  • Unknown/Other: application/octet-stream

Examples

JavaScript Example

const apiHost = 'http://localhost:8080';
const emailId = 'a1b2c3d4e5f6789012345678abcdef90';
const attachmentId = 1;

async function downloadAttachment(emailId, attachmentId) {
    try {
        const response = await fetch(
            `${apiHost}/api/mail/${emailId}/attachment/${attachmentId}`
        );

        if (!response.ok) {
            throw new Error(`HTTP error! status: ${response.status}`);
        }

        // Get filename from Content-Disposition header
        const contentDisposition = response.headers.get('Content-Disposition');
        const filenameMatch = contentDisposition.match(/filename="(.+)"/);
        const filename = filenameMatch ? filenameMatch[1] : `attachment_${attachmentId}`;

        // Get metadata from custom headers
        const attachmentIdHeader = response.headers.get('X-Attachment-ID');
        const emailIdHeader = response.headers.get('X-Email-ID');

        console.log(`Downloading: ${filename}`);
        console.log(`Email ID: ${emailIdHeader}`);
        console.log(`Attachment ID: ${attachmentIdHeader}`);

        // Get the file blob
        const blob = await response.blob();

        // Create download link
        const url = window.URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = filename;
        document.body.appendChild(a);
        a.click();

        // Cleanup
        window.URL.revokeObjectURL(url);
        document.body.removeChild(a);

        console.log('Download initiated successfully');
    } catch (error) {
        console.error('Error downloading attachment:', error);
    }
}

downloadAttachment(emailId, attachmentId);

cURL Example

# Download attachment and save with original filename
curl -X GET "http://localhost:8080/api/mail/a1b2c3d4e5f6789012345678abcdef90/attachment/1" \
  -J -O

# Download and view headers
curl -X GET "http://localhost:8080/api/mail/a1b2c3d4e5f6789012345678abcdef90/attachment/1" \
  -i -o attachment.bin

# Download to specific filename
curl -X GET "http://localhost:8080/api/mail/a1b2c3d4e5f6789012345678abcdef90/attachment/1" \
  -o "downloaded_invoice.pdf"

Go Example

package main

import (
    "fmt"
    "io"
    "net/http"
    "os"
    "regexp"
)

const apiHost = "http://localhost:8080"

func downloadAttachment(emailID string, attachmentID int) error {
    // Build URL
    url := fmt.Sprintf("%s/api/mail/%s/attachment/%d", apiHost, emailID, attachmentID)

    // Make GET request
    resp, err := http.Get(url)
    if err != nil {
        return fmt.Errorf("request failed: %w", err)
    }
    defer resp.Body.Close()

    if resp.StatusCode != http.StatusOK {
        return fmt.Errorf("unexpected status: %s", resp.Status)
    }

    // Extract filename from Content-Disposition header
    contentDisposition := resp.Header.Get("Content-Disposition")
    re := regexp.MustCompile(`filename="(.+)"`)
    matches := re.FindStringSubmatch(contentDisposition)

    filename := fmt.Sprintf("attachment_%d", attachmentID)
    if len(matches) > 1 {
        filename = matches[1]
    }

    // Get metadata from custom headers
    attachmentIDHeader := resp.Header.Get("X-Attachment-ID")
    emailIDHeader := resp.Header.Get("X-Email-ID")

    fmt.Printf("Downloading: %s\n", filename)
    fmt.Printf("Email ID: %s\n", emailIDHeader)
    fmt.Printf("Attachment ID: %s\n", attachmentIDHeader)

    // Create output file
    outFile, err := os.Create(filename)
    if err != nil {
        return fmt.Errorf("failed to create file: %w", err)
    }
    defer outFile.Close()

    // Write response body to file
    bytesWritten, err := io.Copy(outFile, resp.Body)
    if err != nil {
        return fmt.Errorf("failed to write file: %w", err)
    }

    fmt.Printf("Downloaded %d bytes to %s\n", bytesWritten, filename)
    return nil
}

func main() {
    emailID := "a1b2c3d4e5f6789012345678abcdef90"
    attachmentID := 1

    if err := downloadAttachment(emailID, attachmentID); err != nil {
        fmt.Printf("Error: %v\n", err)
        os.Exit(1)
    }
}

Related Endpoints

/mail/{id}/attachments

Get a list of all attachments for a specific email with metadata including IDs, names, and sizes.