Get Attachment
Download a message attachment via presigned URL
Endpoints
GET /v1/inboxes/{id}/messages/{msgId}/attachments/{attachId}- Download via message pathGET /v1/inboxes/{id}/threads/{threadId}/messages/{msgId}/attachments/{attachId}- Download via thread path
Both endpoints return the same result - use whichever is more convenient for your agent's context.
Authentication
Requires the inbox's API key in the Authorization header.
Path Parameters
idstringpathrequiredInbox ID (e.g., inb_abc123)
msgIdstringpathrequiredMessage ID (e.g., msg_xyz789)
attachIdstringpathrequiredAttachment ID (e.g., att_ghi012)
threadIdstringpathThread ID (only for thread path variant)
Request
# Get presigned URL
curl -X GET "https://api.daimon.email/v1/inboxes/inb_abc123/messages/msg_xyz789/attachments/att_ghi012" \
-H "Authorization: Bearer dm_free_7d8a9b0c1d2e3f4g5h6i7j8k9l0m1n2o"
# Then download the file
# curl -X GET "<presigned_url>" -o downloaded_file.pdfconst client = new DaimonClient({ apiKey: 'dm_free_...' });
// Get presigned download URL
const attachment = await client.inboxes.messages.attachments.get(
'inb_abc123',
'msg_xyz789',
'att_ghi012'
);
console.log(`Download URL: ${attachment.url}`);
console.log(`Expires at: ${attachment.expires_at}`);
console.log(`Filename: ${attachment.filename}`);
console.log(`Size: ${attachment.size} bytes`);
// Download the file
const response = await fetch(attachment.url);
const blob = await response.blob();
const buffer = Buffer.from(await blob.arrayBuffer());
// Save to disk
import fs from 'fs';
fs.writeFileSync(attachment.filename, buffer);
console.log(`Downloaded: ${attachment.filename}`);client = DaimonClient(api_key='dm_free_...')
# Get presigned download URL
attachment = client.inboxes.messages.attachments.get(
'inb_abc123',
'msg_xyz789',
'att_ghi012'
)
print(f"Download URL: {attachment.url}")
print(f"Expires at: {attachment.expires_at}")
print(f"Filename: {attachment.filename}")
print(f"Size: {attachment.size} bytes")
# Download the file
import requests
response = requests.get(attachment.url)
with open(attachment.filename, 'wb') as f:
f.write(response.content)
print(f"Downloaded: {attachment.filename}")Response
Response
{
"result": {
"url": "https://r2.cloudflarestorage.com/daimon-email/attachments/inb_abc123/msg_xyz789/att_ghi012.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...",
"expires_at": "2024-03-11T15:35:20Z",
"filename": "welcome.pdf",
"content_type": "application/pdf",
"size": 45678
},
"next_steps": [
"Download the file using the presigned URL",
"URL expires in 1 hour - request a new URL if needed",
"Use content_type to determine how to process the file"
]
}{
"error": "ATTACHMENT_NOT_FOUND",
"message": "Attachment att_ghi012 not found in message msg_xyz789",
"next_steps": [
"Verify the attachment ID is correct",
"Check GET /v1/inboxes/{id}/messages/{msgId} for available attachments"
]
}Response Fields
result.urlstringPresigned R2 download URL - valid for 1 hour
result.expires_atstringISO 8601 timestamp of when the presigned URL expires
result.filenamestringOriginal filename from the email attachment
result.content_typestringMIME type (e.g., application/pdf, image/png, text/csv)
result.sizeintegerFile size in bytes
next_stepsarrayAgent guidance for next actions
Presigned URL Behavior
Request presigned URL
Call this endpoint to get a temporary download URL
URL valid for 1 hour
The presigned URL expires after 1 hour for security
Download directly from R2
Use the URL to download the file directly from Cloudflare R2 - no API key needed
Request new URL if expired
If the URL expires, call this endpoint again to get a fresh presigned URL
Info
No authentication required for presigned URLs - the signature is embedded in the URL itself. This allows agents to download files without exposing their API keys.
Use Cases
Download all attachments from a message
const message = await client.inboxes.messages.get('inb_abc123', 'msg_xyz789');
console.log(`Message has ${message.attachments.length} attachments`);
for (const att of message.attachments) {
const download = await client.inboxes.messages.attachments.get(
'inb_abc123',
message.id,
att.id
);
// Download file
const response = await fetch(download.url);
const buffer = Buffer.from(await response.arrayBuffer());
// Save to disk
fs.writeFileSync(`downloads/${download.filename}`, buffer);
console.log(`Downloaded: ${download.filename} (${download.size} bytes)`);
}Filter by file type
const message = await client.inboxes.messages.get('inb_abc123', 'msg_xyz789');
// Only download PDF attachments
const pdfAttachments = message.attachments.filter(
att => att.content_type === 'application/pdf'
);
for (const att of pdfAttachments) {
const download = await client.inboxes.messages.attachments.get(
'inb_abc123',
message.id,
att.id
);
// Process PDF...
console.log(`PDF: ${download.filename}`);
}Process image attachments with vision AI
const message = await client.inboxes.messages.get('inb_abc123', 'msg_xyz789');
const imageAttachments = message.attachments.filter(
att => att.content_type.startsWith('image/')
);
for (const att of imageAttachments) {
const download = await client.inboxes.messages.attachments.get(
'inb_abc123',
message.id,
att.id
);
// Download image
const response = await fetch(download.url);
const buffer = Buffer.from(await response.arrayBuffer());
// Process with vision AI
const analysis = await visionAI.analyze(buffer);
console.log(`Image analysis: ${analysis.description}`);
}Check attachment size before downloading
const message = await client.inboxes.messages.get('inb_abc123', 'msg_xyz789');
const MAX_SIZE = 10 * 1024 * 1024; // 10MB
for (const att of message.attachments) {
if (att.size > MAX_SIZE) {
console.log(`Skipping large attachment: ${att.filename} (${att.size} bytes)`);
continue;
}
// Download small attachments only
const download = await client.inboxes.messages.attachments.get(
'inb_abc123',
message.id,
att.id
);
// Process...
}Handle expired presigned URLs
async function downloadWithRetry(inboxId, messageId, attachmentId) {
let download = await client.inboxes.messages.attachments.get(
inboxId,
messageId,
attachmentId
);
// Try download
let response = await fetch(download.url);
// If expired, get new URL
if (response.status === 403) {
console.log('URL expired, requesting new presigned URL...');
download = await client.inboxes.messages.attachments.get(
inboxId,
messageId,
attachmentId
);
response = await fetch(download.url);
}
return response;
}
const response = await downloadWithRetry('inb_abc123', 'msg_xyz789', 'att_ghi012');
const buffer = Buffer.from(await response.arrayBuffer());Common MIME Types
Documents
application/pdf- PDF filesapplication/msword- Word (.doc)application/vnd.openxmlformats-officedocument.wordprocessingml.document- Word (.docx)application/vnd.ms-excel- Excel (.xls)application/vnd.openxmlformats-officedocument.spreadsheetml.sheet- Excel (.xlsx)text/plain- Plain texttext/csv- CSV files
Images
image/png- PNGimage/jpeg- JPEG/JPGimage/gif- GIFimage/webp- WebPimage/svg+xml- SVG
Archives
application/zip- ZIPapplication/x-tar- TARapplication/gzip- GZIPapplication/x-7z-compressed- 7Z