Table of Contents

Large files

Send large files without loading them into memory, and track the progress of the send.

Prerequisites

A send with attachments that already works: see Attachments.

From disk, not from memory

Way Behaviour Use
FilesPath (file paths) The SDK reads each file in 512 KiB chunks: the file is never fully loaded into memory. Large files.
filesList (content in memory) The file is already fully in memory before the send. Small files produced by your application.

For a large file, always pass its path.

Track progress

var fileHelper = new FileHelper();
var chunks = new ConcurrentDictionary<long, bool>();   // chunks of the current file

fileHelper.UploadFileStart_Event += (name, size) => chunks.Clear();
fileHelper.UploadChunkCompleted_Event += (name, size, index, total) =>
{
    // Called from several threads, out of order, sometimes twice for the same chunk.
    chunks.TryAdd(index, true);
    ShowProgress((int)Math.Min(100, chunks.Count * 100L / total));
};
fileHelper.UploadFileEnd_Event += (name, size) => ShowProgress(100);

var args = new MutliRecipientArgs(
    endPointUri: endpoint, serial: serial, user: apiUser, psw: apiPassword,
    recipients: recipients, message: message, subject: subject,
    password: null, filesList: null,
    sendMode: SendMethodEnum.onlyEmail, getBackHtml: false,
    showSubject: true, getNotify: true, cultureID: "en-CA",
    maximumOpenTime: 5, minutesExpiration: 10080)
{
    FilesPath = new List<string> { filePath },
};

// Pass your FileHelper: without it, the SDK creates its own and your events never fire.
var response = MessageHelper.MultiRecipientMessage(args, fileHelper);

Only consider a file sent at the end of the call, after checking the status of the send: a chunk can still fail after progress has reached 100%.

UploadChunkCompleted_Event also fires for a chunk the server has not confirmed, then again when it is resent: count distinct indexes, as in the example. Avoid UploadEvent and GetFileSizeBeforeUpload: they are static events, shared by the whole process.

on_upload_progress and on_upload_finish exist in FileHelper but are never called: use the callbacks of the example.

$onUploadProgress and $onUploadFinish exist in FileHelper but are never called: use the callbacks of the example.

Good to know

Point Detail
Chunk size 512 KiB, fixed.
Parallel uploads .NET: NbThreadUploads, from 1 to 10 (6 by default). Python: 4 chunks at a time, not adjustable from the send. PHP: one chunk at a time.
Retries A failed chunk is resent, up to 10 more passes one second apart. After that, the send fails (status 500) and no message is sent.
Resume None between two calls: a new send uploads every file again.
Timeout per request 5 minutes in .NET 8, 120 seconds in Python and PHP; not adjustable.
Maximum size The SDK imposes none: your plan's limit is applied by the server. See Licence and quotas. An empty file is refused.
Hash The SDK computes a SHA-512 hash of each file, checked on reception. Above 1 GB, it is computed by blocks: it differs from the SHA-512 of the whole file (sha512sum, for example).
Warning

In .NET, a path not found in FilesPath is ignored without error: the message goes out without that file, with status 200. Check that each file exists before sending.

Common errors

Symptom Likely cause Solution
Status 500 after a long wait A chunk failed after every retry: unstable network or timeout Try again later; on a slow network, reduce the number of parallel uploads (.NET).
Status 500 "Access denied" More than 10 refusals from the server during the send Check your credentials, the environment and your licence's permissions.
.NET: events never fire FileHelper not passed to MessageHelper.MultiRecipientMessage Use the MessageHelper.MultiRecipientMessage(args, fileHelper) overload.
.NET: SettingsHelper.NbThreadUploads = 4 does not compile It is a constant (former guide) Set NbThreadUploads in the send arguments.
"File 0 ko length error" Empty file Remove it from the send.

Next