\r\n [or CRLF] in --send-mail-body

So, I include more than %result% in my --send-mail-body - and I want to have \n\r [carriage return & linefeed] between each item.

Something like this:
–send-mail-body="%OPERATIONNAME% \r\b %backup-name% \r\n %result%"

Is there some character I can use to insert CRLF. [\r\n doesn’t work.]

If not, is there some other method that’s fairly straight-forward?

[Namely, I’m listing the source/dest/job-name/etc - and it does that fine. However it’s all just jammed together. I’d like each thing on a new line.]

Oh, BTW, if I put “pipe” | characters in the send-mail-body the email fails. I suspect this is a quasi-bug that ought to get a quick look. [I tried using the pipe character as a separator since I couldn’t get CRLF’s working.]

I’m not sure about the line feeds, but in curious about the pipe issue - what OS are you using?

Windows is the only OS I’ve tried using a pipe on, so I know it happens there.
Have no data about other platforms.

So, no one has any great idea how to get a CRLF in the body?

I still haven’t gotten around to testing, but does using an HTML br tag work?

1 Like

Does supplying a template from a file (full path from the root) work? This seems well documented but I had to discover it by reading source to see if there was any way to line-break from the directly supplied template. :blush:

Agreed with @JonMikelV - first thing I’d try is <br/> .

Html < br > tag causes the same issues as | “pipe.” [I’d type it without spaces, but it just produces a break, in the message I’m posting. :slight_smile: ]
The mail never gets sent. To be clear, it never hits the mail server - apparently duplicati bombs/fails when sending the email.

No error messages, no warnings, (at the console or elsewhere) just no email.

D’Oh! I should have figured Windows would see that as a redirect.

I think we need a non-windows test to see what works vs. what needs to be escaped for Windows.

I’m still offering the documented solution. It seems fairly straight-forward, though it does use a separate file…

--send-mail-body (String): The message body This value can be a filename. If the file exists, the file contents will be used as the message body.
EDIT: not quoting the whole thing here. Refer to documentation link above or below for the entire description.

So, how do I add these items to the file, after running the backup, but before the email would be sent?

In case it’s not clear, I want [this may not be an exhaustive or exclusive list, but if someone can show me how to manage these items, I am pretty sure I can stumble my way though most anything else I need.]

Backup Name: %backup-name%
BackupFrom: %LOCALPATH%
Operation Name: %OPERATIONNAME%
Full Result: %RESULT%

I’m sure I can generate my own email, but that’s a lot of hassle. I’ve done it that way in the past, using powershell - but that requires a lot of tinkering on each station you’re going to setup duplicati.I really want something that’s as bog-standard as possible. Adding a line like this:

–send-mail-body=Backup Name: %backup-name% ; BackupFrom: %LOCALPATH% ; Operation Name: %OPERATIONNAME% ; Result: %PARSEDRESULT% ; Full Result: %RESULT%

…Well, that’s a lot cleaner, quicker, easier to maintain, uniform etc.

And while hard-returns would be really nice, I’ll keep doing it without, unless there’s some really stream-lined way to do it in a file.

I hate to be a curmudgeon, but simply having a way to drop some hard-returns in the body provided in the CLI/config is far more elegant, IMO, than somehow loading a file with the text you want.

The less I have to modify for each install, the better. The less I tweak the process to use non-native options, etc - well even better.

All that said, explain how I’d load this file with the text I want, and perhaps it’s not as ugly as I fear.


I copy-and-pasted your item format into notepad, saved it, pointed to the file, ran a backup, got this email:

Backup Name: local test 4
BackupFrom: C:\Users\Ted\Documents\size test 2\short.txt
Operation Name: Backup
Result: Success
Full Result: DeletedFiles: 0
DeletedFolders: 0
ModifiedFiles: 1
ExaminedFiles: 1
OpenedFiles: 1
AddedFiles: 0
SizeOfModifiedFiles: 0
SizeOfAddedFiles: 0
SizeOfExaminedFiles: 26
SizeOfOpenedFiles: 26
NotProcessedFiles: 0
AddedFolders: 0
TooLargeFiles: 0
FilesWithError: 0
ModifiedFolders: 0
ModifiedSymlinks: 0
AddedSymlinks: 0
DeletedSymlinks: 0
PartialBackup: False
Dryrun: False
MainOperation: Backup
ParsedResult: Success
Version: (
EndTime: 10/25/2018 10:06:01 PM (1540519561)
BeginTime: 10/25/2018 10:05:58 PM (1540519558)
Duration: 00:00:02.6205839

There would have been blank lines if the template had any. Substitutions are as usual per –send-mail-body which for this test was --send-mail-body=C:\Templates\Template.txt, but standardize it as you wish.

Ah! I wouldn’t have thought that the parameter substitution would work in the external file - so I was really confused as to how this would be accomplished.

But with substitution, it makes perfect sense.

I’m still not in-love with the idea - but it’s certainly work able.

Thanks a bunch for the example!

PS. And if I understand it up-thread - you have to provide the entire path to the file, not just a relative path. [Mostly for the benefit of those who find this result in a search.]

The code, just before reading the file, runs IsPathRooted so relative “should” not work. Relative also raises a question of relative-to-what, especially because Duplicati is often in C:\Program Files\Duplicati 2, but updates might move its current directory somewhere else. I haven’t gone to check. It just seems a bad thing to rely on.

Good point - @kenkendk, can you clarify whether relative paths are based on install or updates folder?

In testing with Process Explorer, the answer at least for some Command Prompt launches was it stayed right where the current directory was at its launch, which possibly is also what the Service does. Basically, it’s not something to rely on. Microsoft gave additional cautions in the File path formats on Windows systems article:


Relative paths are dangerous in multithreaded applications (that is, most applications) because the current directory is a per-process setting. Any thread can change the current directory at any time. Starting with .NET Core 2.1, you can call the Path.GetFullPath(String, String) method to get an absolute path from a relative path and the base path (the current directory) that you want to resolve it against.

I think users should not be using relative paths either, because where they go to isn’t guaranteed (I believe).