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
string
required
Original filename (e.g.,
report.pdf). Used for display in email clients.string
required
MIME type of the file (e.g.,
application/pdf, image/png).integer
required
File size in bytes. Maximum 40MB for regular attachments, 5MB for inline images.
boolean
default:"false"
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
string
Unique attachment ID to use when sending emails.
string
Presigned URL for uploading the file. PUT your file here.
string
ISO 8601 timestamp when the upload URL expires (typically 1 hour).
string
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 |