How to base64-encode excel for the microsoft graph /sendmail attachment
- Step 1Upload the report — Drop the
.xlsx/.xls/.ods/.csvyou want to attach. Only spreadsheet extensions are selectable. - Step 2Encode locally —
file.arrayBuffer()reads the bytes; chunkedbtoa()encodes them with no server round-trip. - Step 3Check it's under ~3 MB — Read line 1's byte count. Inline
sendMailattachments are limited to roughly 3 MB; over that, use an upload session. - Step 4Copy and strip the header — Copy the whole block, then delete the two
//lines and the blank line. What's left iscontentBytes. - Step 5Use the printed MIME for contentType — Line 2 is the exact value for the
contentTypeproperty. - Step 6Build the fileAttachment object — Assemble
{ '@odata.type': '#microsoft.graph.fileAttachment', name, contentType, contentBytes }inside the message's attachments array.
Graph fileAttachment object fields
How the tool's two outputs populate a #microsoft.graph.fileAttachment. Values shown are for an .xlsx report.
| Field | Value source | Example |
|---|---|---|
@odata.type | Constant | #microsoft.graph.fileAttachment |
name | Your filename | report.xlsx |
contentType | Tool's MIME line (Line 2) | application/vnd.openxmlformats-officedocument.spreadsheetml.sheet |
contentBytes | Tool's raw Base64 (Line 4+, header stripped) | UEsDBBQABg... |
Graph attachment paths by size
Inline vs. upload-session depends on file size. The tool's inline Base64 is only appropriate below the inline ceiling.
| File size | Graph approach | Use this tool's output? |
|---|---|---|
| Up to ~3 MB | Inline contentBytes in the sendMail request body | Yes — paste as contentBytes |
| ~3 MB to 150 MB | Create a draft message, then upload via attachment upload session | Partially — you still need the bytes, but not inline |
| Over 150 MB | Not supported as a mail attachment | No — share a link instead |
File-size limits by plan (excel family)
The JAD plan cap governs what you can encode; Graph's inline ~3 MB ceiling governs what you can send inline. Encode within both.
| Plan | Max source file | Approx. Base64 output (+33%) | Files per run |
|---|---|---|---|
| Free | 5 MB | ~6.7 MB | 1 |
| Pro | 50 MB | ~66.5 MB | 5 |
| Pro-media | 200 MB | ~266 MB | 20 |
| Developer | 500 MB | ~665 MB | unlimited |
Cookbook
Graph-shaped requests built from the tool's literal output. contentBytes is always the raw Base64 with the // header removed.
sendMail with an inline Excel attachment
The standard small-attachment pattern: contentBytes from the tool, contentType from line 2.
Tool output:
// Base64-encoded: report.xlsx (1,204,880 bytes)
// MIME type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
UEsDBBQABg...
POST /v1.0/me/sendMail
{
"message": {
"subject": "Monthly report",
"toRecipients": [{ "emailAddress": { "address": "client@acme.com" } }],
"attachments": [{
"@odata.type": "#microsoft.graph.fileAttachment",
"name": "report.xlsx",
"contentType": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"contentBytes": "UEsDBBQABg..."
}]
}
}Confirm the file is under the inline ceiling
Inline attachments are limited to ~3 MB. Read the byte count before you build the request.
// header: report.xlsx (1,204,880 bytes ≈ 1.2 MB) 1.2 MB < ~3 MB inline limit -> OK to send inline
contentBytes must be raw — no data: prefix
Graph rejects a contentBytes value that includes a data URI. The tool already emits raw Base64; just strip the comment header.
WRONG: "contentBytes": "data:application/...;base64,UEsDBBQABg..." RIGHT: "contentBytes": "UEsDBBQABg..." <- tool's raw output, header removed
Attach to an existing draft message
For the upload-session path you still encode the bytes the same way, then POST them to the message's attachments collection.
POST /v1.0/me/messages/{id}/attachments
{
"@odata.type": "#microsoft.graph.fileAttachment",
"name": "report.xlsx",
"contentType": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"contentBytes": "UEsDBBQABg..."
}Teams channel message small-file attachment
Teams attachments via Graph use the same Base64 contentBytes pattern for small hosted-content items.
// reuse the same raw Base64 + contentType the tool printed "contentBytes": "UEsDBBQABg...", "contentType": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
Edge cases and what actually happens
Inline attachment over ~3 MB
Request rejectedGraph's inline sendMail attachment limit is roughly 3 MB. For larger files, create a draft and use an attachment upload session — the inline contentBytes pattern won't work.
data: prefix left in contentBytes
Invalid attachmentGraph expects raw Base64 only. The tool emits raw Base64, but if you added a data: prefix manually, remove it.
Comment header copied into contentBytes
Invalid attachmentThe Copy button includes the two // lines. If they end up in contentBytes, the attachment is corrupt — strip the first three lines.
contentType is application/octet-stream
Wrong file type in OutlookIf the browser couldn't classify the file, set the correct Office MIME in contentType manually so Outlook shows it as a spreadsheet.
Encoding a .csv for Graph
SupportedCSV encodes fine; use text/csv (printed) as contentType. Recipients open it in Excel by default on most systems.
Free tier on a 6 MB workbook
RejectedFree caps at 5 MB source. Even on a higher plan, recall the inline Graph limit is ~3 MB — so trimming the workbook helps on both counts.
Truncated Base64 from a large copy
Corrupt attachmentLong strings can lose characters on copy. Download name.b64.txt and verify decoded length equals the header byte count.
Need OneDrive large-file share instead
By designFor files too big to inline, upload to OneDrive via Graph and send a sharing link rather than Base64-encoding the file here.
Sensitive workbook with hidden data
Use sibling toolsBefore emailing, strip hidden sheets with the Hidden Sheet Destroyer and audit external links with the External Link Auditor, then encode.
Frequently asked questions
What's the max attachment size for Graph sendMail?
Inline attachments in the request body are limited to roughly 3 MB. For larger files, use a draft message plus an attachment upload session instead of inline contentBytes.
Should contentBytes include the data URI prefix?
No. Graph expects raw Base64 only, which is what this tool emits — just strip the two // comment lines first.
Which output line becomes contentType?
Line 2 (the MIME line). For .xlsx it's application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.
Which part is contentBytes?
The raw Base64 below the blank line, with the // header removed.
Does the corporate file get uploaded to encode it?
No — encoding is fully browser-side via file.arrayBuffer() and btoa(). The file stays local.
Can I use this for Teams or calendar attachments via Graph?
Yes. Those also use the Base64 contentBytes pattern for small files; reuse the same raw string and contentType.
What if my file is larger than the inline limit?
Create a draft message and upload the attachment via an upload session (supports much larger files), or share a OneDrive link instead.
Why does Outlook show my attachment as a generic file?
Likely a wrong contentType (e.g. application/octet-stream). Set the correct Office MIME so it's recognised as a spreadsheet.
What file types can I encode here?
.xlsx, .xls, .ods, .csv. Other types aren't selectable in this tool.
What's the JAD encoding size limit?
Free 5 MB, Pro 50 MB, Pro-media 200 MB, Developer 500 MB on the source — separate from Graph's ~3 MB inline ceiling.
Can I decode contentBytes back to a file here?
Not yet — decoding is planned. Use atob() or a decoder for now.
What should I do before sending a sensitive report?
Remove hidden sheets with the Hidden Sheet Destroyer and check links with the External Link Auditor, then encode the clean file.
Privacy first
Every JAD Excel tool runs entirely in your browser using SheetJS and ExcelJS. Your spreadsheets, formulas, and data never leave your device — verified by zero outbound network requests during processing.