Create Attachment Upload
curl --request POST \
--url https://api.example.com/api/v1/attachments/presigned-url \
--header 'Content-Type: application/json' \
--data '
{
"filename": "<string>",
"contentType": "<string>",
"size": 123,
"inline": true
}
'import requests
url = "https://api.example.com/api/v1/attachments/presigned-url"
payload = {
"filename": "<string>",
"contentType": "<string>",
"size": 123,
"inline": True
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({filename: '<string>', contentType: '<string>', size: 123, inline: true})
};
fetch('https://api.example.com/api/v1/attachments/presigned-url', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.example.com/api/v1/attachments/presigned-url",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'filename' => '<string>',
'contentType' => '<string>',
'size' => 123,
'inline' => true
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/api/v1/attachments/presigned-url"
payload := strings.NewReader("{\n \"filename\": \"<string>\",\n \"contentType\": \"<string>\",\n \"size\": 123,\n \"inline\": true\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.example.com/api/v1/attachments/presigned-url")
.header("Content-Type", "application/json")
.body("{\n \"filename\": \"<string>\",\n \"contentType\": \"<string>\",\n \"size\": 123,\n \"inline\": true\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/api/v1/attachments/presigned-url")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"filename\": \"<string>\",\n \"contentType\": \"<string>\",\n \"size\": 123,\n \"inline\": true\n}"
response = http.request(request)
puts response.read_body{
"attachmentId": "<string>",
"uploadUrl": "<string>",
"expiresAt": "<string>",
"contentId": "<string>"
}Attachments
Create Attachment Upload
Generate a presigned URL for uploading an attachment
POST
/
api
/
v1
/
attachments
/
presigned-url
Create Attachment Upload
curl --request POST \
--url https://api.example.com/api/v1/attachments/presigned-url \
--header 'Content-Type: application/json' \
--data '
{
"filename": "<string>",
"contentType": "<string>",
"size": 123,
"inline": true
}
'import requests
url = "https://api.example.com/api/v1/attachments/presigned-url"
payload = {
"filename": "<string>",
"contentType": "<string>",
"size": 123,
"inline": True
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({filename: '<string>', contentType: '<string>', size: 123, inline: true})
};
fetch('https://api.example.com/api/v1/attachments/presigned-url', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.example.com/api/v1/attachments/presigned-url",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'filename' => '<string>',
'contentType' => '<string>',
'size' => 123,
'inline' => true
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/api/v1/attachments/presigned-url"
payload := strings.NewReader("{\n \"filename\": \"<string>\",\n \"contentType\": \"<string>\",\n \"size\": 123,\n \"inline\": true\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.example.com/api/v1/attachments/presigned-url")
.header("Content-Type", "application/json")
.body("{\n \"filename\": \"<string>\",\n \"contentType\": \"<string>\",\n \"size\": 123,\n \"inline\": true\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/api/v1/attachments/presigned-url")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"filename\": \"<string>\",\n \"contentType\": \"<string>\",\n \"size\": 123,\n \"inline\": true\n}"
response = http.request(request)
puts response.read_body{
"attachmentId": "<string>",
"uploadUrl": "<string>",
"expiresAt": "<string>",
"contentId": "<string>"
}Create a presigned URL for uploading an email attachment. After uploading the file to this URL, you must confirm the upload before using the attachment.
Upload Flow
Attachments use a three-step process:- Create Upload - Get a presigned URL (this endpoint)
- Upload File - PUT the file directly to the presigned URL
- Confirm Upload - Notify MailBreeze the upload is complete
- Use Attachment - Include attachment ID when sending emails
Request Body
Original filename (e.g.,
report.pdf). Used for display in email clients.MIME type of the file (e.g.,
application/pdf, image/png).File size in bytes. Maximum 40MB for regular attachments, 5MB for inline images.
Set to
true for embedded images in HTML emails (returns contentId).Examples
import { MailBreeze } from "mailbreeze";
const mailbreeze = new MailBreeze({ apiKey: "sk_live_xxx" });
// Step 1: Create upload URL
const { attachmentId, uploadUrl, uploadToken, expiresAt } =
await mailbreeze.attachments.createUpload({
fileName: "report.pdf",
contentType: "application/pdf",
fileSize: 1024000, // ~1MB
});
console.log(`Upload URL expires at: ${expiresAt}`);
// Step 2: Upload file directly to the presigned URL
const fileBuffer = await fs.readFile("./report.pdf");
await fetch(uploadUrl, {
method: "PUT",
body: fileBuffer,
headers: {
"Content-Type": "application/pdf",
"Content-Length": fileBuffer.length.toString(),
},
});
// Step 3: Confirm the upload
const attachment = await mailbreeze.attachments.confirm({ uploadToken });
console.log(attachment.status); // "uploaded"
// Step 4: Use in email
await mailbreeze.emails.send({
from: "hello@yourdomain.com",
to: "user@example.com",
subject: "Your report is ready",
html: "<p>Please find your report attached.</p>",
attachmentIds: [attachmentId],
});
import aiohttp
from mailbreeze import MailBreeze
client = MailBreeze(api_key="sk_live_xxx")
# Step 1: Create upload URL
result = await client.attachments.create_upload(
file_name="report.pdf",
content_type="application/pdf",
file_size=1024000,
)
print(f"Upload URL expires at: {result.expires_at}")
# Step 2: Upload file directly
with open("./report.pdf", "rb") as f:
file_data = f.read()
async with aiohttp.ClientSession() as session:
await session.put(
result.upload_url,
data=file_data,
headers={"Content-Type": "application/pdf"},
)
# Step 3: Confirm the upload
attachment = await client.attachments.confirm(upload_token=result.upload_token)
print(attachment.status) # "uploaded"
# Step 4: Use in email
await client.emails.send(
from_="hello@yourdomain.com",
to="user@example.com",
subject="Your report is ready",
html="<p>Please find your report attached.</p>",
attachment_ids=[result.attachment_id],
)
client := mailbreeze.NewClient("sk_live_xxx")
// Step 1: Create upload URL
result, err := client.Attachments.CreateUpload(ctx, &mailbreeze.CreateAttachmentUploadParams{
FileName: "report.pdf",
ContentType: "application/pdf",
FileSize: 1024000,
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("Upload URL expires at: %s\n", result.ExpiresAt)
// Step 2: Upload file directly
fileData, _ := os.ReadFile("./report.pdf")
req, _ := http.NewRequest("PUT", result.UploadURL, bytes.NewReader(fileData))
req.Header.Set("Content-Type", "application/pdf")
http.DefaultClient.Do(req)
// Step 3: Confirm the upload
attachment, err := client.Attachments.Confirm(ctx, &mailbreeze.ConfirmAttachmentParams{
UploadToken: result.UploadToken,
})
// Step 4: Use in email
client.Emails.Send(ctx, &mailbreeze.SendEmailParams{
From: "hello@yourdomain.com",
To: []string{"user@example.com"},
Subject: "Your report is ready",
HTML: "<p>Please find your report attached.</p>",
AttachmentIds: []string{result.AttachmentID},
})
$mailbreeze = new MailBreeze('sk_live_xxx');
// Step 1: Create upload URL
$response = $mailbreeze->attachments->createUpload([
'fileName' => 'report.pdf',
'contentType' => 'application/pdf',
'fileSize' => 1024000,
]);
$result = $response['data'];
echo "Upload URL expires at: " . $result['expiresAt'] . "\n";
// Step 2: Upload file directly
$fileData = file_get_contents('./report.pdf');
$ch = curl_init($result['uploadUrl']);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
curl_setopt($ch, CURLOPT_POSTFIELDS, $fileData);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/pdf']);
curl_exec($ch);
curl_close($ch);
// Step 3: Confirm the upload
$attachment = $mailbreeze->attachments->confirm($result['attachmentId']);
// Step 4: Use in email
$mailbreeze->emails->send([
'from' => 'hello@yourdomain.com',
'to' => 'user@example.com',
'subject' => 'Your report is ready',
'html' => '<p>Please find your report attached.</p>',
'attachmentIds' => [$result['attachmentId']],
]);
let client = Client::new("sk_live_xxx");
// Step 1: Create upload URL
let result = client.attachments().create_upload(CreateAttachmentUploadParams {
file_name: "report.pdf".to_string(),
content_type: "application/pdf".to_string(),
file_size: 1024000,
}).await?;
println!("Upload URL expires at: {}", result.expires_at);
// Step 2: Upload file directly
let file_data = std::fs::read("./report.pdf")?;
reqwest::Client::new()
.put(&result.upload_url)
.header("Content-Type", "application/pdf")
.body(file_data)
.send()
.await?;
// Step 3: Confirm the upload
let attachment = client.attachments().confirm(ConfirmAttachmentParams {
upload_token: result.upload_token,
}).await?;
// Step 4: Use in email
client.emails().send(SendEmailParams {
from: "hello@yourdomain.com".to_string(),
to: vec!["user@example.com".to_string()],
subject: Some("Your report is ready".to_string()),
html: Some("<p>Please find your report attached.</p>".to_string()),
attachment_ids: Some(vec![result.attachment_id]),
..Default::default()
}).await?;
# Step 1: Create presigned upload URL
curl -X POST https://api.mailbreeze.com/api/v1/attachments/presigned-url \
-H "Authorization: Bearer sk_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"filename": "report.pdf",
"contentType": "application/pdf",
"size": 1024000
}'
# Step 2: Upload file to the presigned URL
curl -X PUT "https://storage.mailbreeze.com/..." \
-H "Content-Type: application/pdf" \
--data-binary @report.pdf
# Step 3: (Optional) Confirm upload
curl -X POST https://api.mailbreeze.com/api/v1/attachments/att_abc123/confirm \
-H "Authorization: Bearer sk_live_xxx"
Response
Unique attachment ID to use when sending emails.
Presigned URL for uploading the file. PUT your file here.
ISO 8601 timestamp when the upload URL expires (typically 1 hour).
For inline attachments only. Use this in HTML:
<img src="cid:contentId">.Example Response
{
"success": true,
"data": {
"attachmentId": "att_abc123",
"uploadUrl": "https://storage.mailbreeze.com/uploads/att_abc123?signature=...",
"expiresAt": "2024-01-15T11:30:00Z"
},
"meta": {
"timestamp": "2024-01-15T10:30:00.000Z",
"requestId": "req_abc123",
"path": "/api/v1/attachments/presigned-url"
}
}
Example Response (Inline Image)
{
"success": true,
"data": {
"attachmentId": "att_abc123",
"uploadUrl": "https://storage.mailbreeze.com/uploads/att_abc123?signature=...",
"expiresAt": "2024-01-15T11:30:00Z",
"contentId": "image001"
},
"meta": {
"timestamp": "2024-01-15T10:30:00.000Z",
"requestId": "req_abc123",
"path": "/api/v1/attachments/presigned-url"
}
}
Limits
| Limit | Value |
|---|---|
| Max file size | 10MB |
| Upload URL validity | 1 hour |
| Attachment validity | 7 days after confirmation |
| Max attachments per email | 10 |
| Max total attachment size per email | 25MB |
Errors
| Code | HTTP Status | Description |
|---|---|---|
ATTACHMENT_TOO_LARGE | 400 | File size exceeds 10MB limit |
INVALID_CONTENT_TYPE | 400 | Unsupported MIME type |
VALIDATION_ERROR | 400 | Missing or invalid parameters |
⌘I