Attachments and binary data: MTOM and SwA
Base64 inside the envelope is simple and wasteful. MTOM keeps the XML readable and sends the bytes as raw binary alongside it.
Three ways to send bytes
| Approach | On the wire | Overhead | Interoperability |
|---|---|---|---|
| Inline base64 | Text inside the body | About 33 percent larger, and it all sits in memory | Universal |
| SwA (SOAP with Attachments) | A MIME multipart with the XML in part 0 | Low | Poor; WS-I excluded it |
| MTOM with XOP | A MIME multipart where the XML has xop:Include references | Low | Good on modern stacks |
| Out of band | A URL in the body, bytes fetched separately | Lowest for the message | Best for large files, but the link must be secured |
<!-- MTOM: the XML stays the message, the bytes are referenced -->
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Body>
<Upload xmlns="urn:example:files">
<name>scan.pdf</name>
<content>
<xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include"
href="cid:[email protected]"/>
</content>
</Upload>
</soap:Body>
</soap:Envelope>
<!-- The multipart body then contains:
Content-Type: application/octet-stream
Content-Transfer-Encoding: binary
Content-ID: <[email protected]>
...raw PDF bytes... -->Content-Type: multipart/related; type="application/xop+xml";
start="<[email protected]>"; start-info="application/soap+xml";
boundary="MIME_boundary"Practical rules
- Declare the binary element as
xs:base64Binaryin the schema; the MTOM optimisation is then applied by the framework and does not change the contract. - Enable MTOM on both ends. A server sending XOP to a client that expects base64 fails at parse time with a confusing error.
- Stream, do not buffer. A service that reads a 200 MB attachment into a byte array will fail under concurrent load long before the network is the problem.
- Set an explicit maximum message size and reject early with a fault, rather than letting the container buffer until it dies.
- Watch the SOAP engine's own limits: many have a default maximum message size in the low megabytes.
- For files above a few tens of megabytes, prefer a pre-signed upload URL in the body and keep the SOAP message small.
// Enable MTOM on a WCF-style binding and stream the body
var binding = new BasicHttpBinding
{
MessageEncoding = WSMessageEncoding.Mtom,
TransferMode = TransferMode.Streamed,
MaxReceivedMessageSize = 64L * 1024 * 1024,
ReaderQuotas = { MaxArrayLength = 64 * 1024 * 1024 }
};
// TransferMode.Streamed matters more than the size limits:
// it keeps the payload off the managed heap.💡
MTOM is an encoding detail, not a contract change. If you find yourself editing the WSDL to add an attachment, you have probably chosen SwA rather than MTOM, and interoperating with the other vendor's toolkit will be painful.
FAQ
Can I mix inline base64 and MTOM in one service?
Yes, per operation, and it is worth doing: small payloads avoid the multipart overhead while large ones stream. Document which operations use which.
Why is compression not applied automatically?
Binary formats such as PDF and JPEG are already compressed, so gzip wastes CPU for no gain. Compress text or XML attachments only, and always agree the encoding with the partner.
Related
XML Schema and data types in messages Interoperability between .NET, Java and legacy stacks
Last refreshed 2026-09-18.