The email job is a powerful DMSContainer built-in job provided in “the box”. The job email allows to send textual and html email with attachments and related attachments. Moreover, the email job allows to send email with a delay, that’s it, you can plan a send and the job will take care of your message. When you create a new message the email is not send in that moment but is actually sent at the next scheduled run of the job. Usually the email job is scheduled to run each minute or each 5 minutes. A delayed email is send “not before” a specified date, in others word, at the next run after that time stamp. In the next paragraph are listed all the methods available in the email job RPC interface.
Since DMSContainer 4.0.x the Email Module act as DataSource for the EventStreams Module. These means that while its normal activities run, the Email Module emits events in particular queues to notify these activities. In particular any sent email message create a new event in a queue named “queues.jobs..email.sent” and for each sending error creates a new event in a queue named “queues.jobsemail.error”. By default the email module is configured with the name “emails”, so, by default, you will get these messages in the queues “queues.jobs.email.sent” and “queues.jobs.email.sent”. This particular integration open endless possibilities, for instance you can choose to start some process only if an email cannot be sent, o just plug further elaborations when an email is sent and so on. Really, sky is the limit.
The email job uses JWT to do users authentication and authorization. The login method inherited from the Auth Module can be called even in the Email Module and returns a token valid for the next 30 minutes. Any other method but login, requires a valid token as the first parameter.
The Email Module sends email on behalf of a DMS user. It sends email using a specific SMTP configuration called “User’s Sender”. To be able to send emails a DMS user must be configured with a User’s Sender. Check the SetUserSender API for more info.
If you send an email using a professional SMTP client there are two optional features that can be configured:
If you check “delivery receipt”, the “Return-Receipt-To” header field is added to your email. For example:
Return-Receipt-To: "bit Time Professionals" <professionals@bittime.it>
If you check “read receipt”, the “Disposition-Notification-To” header field is added to your email. For example:
Disposition-Notification-To: "bit Time Professionals" <professionals@bittime.it>
The delivery receipt (header Return-Receipt-To) is a request for the receiving mail server to send a Delivery Status Notification (a.k.a. DSN) as soon as it receives the email.
The read receipt (header Disposition-Notification-To) is a request for the receiving email client to send a DSN as soon as the person opens the email.
Both header fields can be added checking “Ask for return receipt” in the “Sender Configuration” form of each user.
However, while the Email Modules does its best to be standard compliant, as the RFC says, ““he presence of a Disposition-Notification-To header in a message is merely a request for an MDN. The recipients’ user agents are always free to silently ignore such a request. Alternatively, an explicit denial of the request for information about the disposition of the message may be sent using the “denied” disposition in an MDN.”
When you send an email to a subscriber and they click ‘Reply’, the reply message is typically sent to the email address listed in the From header.
A Reply-To address is identified by inserting the Reply-To header in your email. It is the email address that the reply message is sent when you want the reply to go to an email address that is different than the From address.
In the example below, ‘professionals@bittime.it’ is the Reply-To address. When a subscriber clicks ‘Reply’, the reply message is sent to ‘professionals@bittime.it’ instead of ‘marketing@bittime.it’.
From: marketing@bittime.com
To: pparker@spideycorporation.com
Reply-To: professionals@sampledomain.com
DMSContainer’ Email Module allows to set a custom Reply-To header setting the property msgreplytolist as defined in the API. Check the samples to know all the details.
The Email Module provides a number of APIs to manage messages, bulk messages (a.k.a. emailing list or newslettera) users and senders.
Allows to log in into the system. It’s inherited by the Auth Module.
Defines a sender for an user. If a user has a sender that user can send emails, otherwise cannot send emails.
PARAMS
token: A valid token
userid: Userid of the user to whom define the sender
obj: A json object with the following properties:
     - senderaddress: The email that will be used to send the email (e.g. peter.parker@bittime.it);
     - smtphost: The smtphost that the user will use to send emails (e.g. smtp.gmail.com);
     - smtpport: The smtpport where the smtpserver listen (e.g. 587);
     - smtpusername: The SMTP username (e.g. peter.parker);
     - smtppassword: The SMTP password (e.g. spidey2000);
     - smtpusessl: A boolean value which defines if the SMTP server needs SSL or not
     - smtpsslversion: One of the following values (as string) depending from the SMTP provider:
       SSLv2, SSLv23, SSLv3, TLSv1, TLSv1_1, TLSv1_2
       This field is ignored if smtpusessl = false
RETURNS
none
REQUIRED ROLES
admin
var
  lResp: IJSONRPCResponse;
  lJSONParam: TJsonObject;
  lJSON: TJsonObject;
  lUserID: Integer;
  lNotification: IJSONRPCNotification;
begin
  lNotification := TJSONRPCNotification.Create('SetUserSender');
  lUserID := 1;
  lNotification.Params.Add(fToken);
  lNotification.Params.Add(lUserID);
  lJSON := TJsonObject.Create;
  lNotification.Params.Add(lJSON);
  lJSON.S['senderaddress'] := 'd.teti@bittime.it';
  lJSON.S['smtphost'] := 'smtp.gmail.com';
  lJSON.I['smtpport'] := 587;
  lJSON.S['smtpusername'] := 'd.teti@bittime.it';
  lJSON.S['smtppassword'] := 'your password';
  lJSON.B['smtpusessl'] := True;
  lJSON.S['smtpsslversion'] := 'TLSv1';
  lResp := fExecutor.ExecuteNotification(lNotification);
  ShowMessage('Sender set for user');
end;
Remove the sender for an user so that it cannot send emails anymore
PARAMS
token: A valid token
userid: The userid of the user to whom remove the sender
RETURNS
none
REQUIRED ROLES
admin
var
  lReq: IJSONRPCRequest;
  lResp: IJSONRPCResponse;
  lJSON: TJsonObject;
  lUserID: Integer;
begin
  lUserID := 99;
  lReq := TJSONRPCRequest.Create(1234, 'removeusersender');
  lReq.Params.Add(fToken);
  lReq.Params.Add(lUserID);
  lResp := fExecutor.ExecuteRequest(lReq);
  ShowMessage('User sender removed');
end;
Add a simple message (without attachments) into the messages queue
PARAMS
token: A valid token
obj: A json object with the following properties:
     - msgtolist: comma separated email address
     - msgcclist: comma separated email address
     - msgbcclist: comma separated email address
     - msgreplytolist: comma separated email address
     - msgsubject: the subject of the email
     - istest: if true the email is not actually sent, used for debug (optional, default false)
     - msgbody: the textual body of the email (optional, default empty)
     - msgbodyhtml: the html body of the email (optional, default empty)
     - msgnote: note for the others user, doesn't affect the sent email (optional, default empty)
RETURNS
messageid: how the message is identified by the system
REQUIRED ROLES
sender
var
  lReq: IJSONRPCRequest;
  lResp: IJSONRPCResponse;
  lJSONParam: TJsonObject;
begin
  lReq := TJSONRPCRequest.Create(1234, 'sendmessage');
  lReq.Params.Add(Token);
  lJSONParam := TJsonObject.Create;
  try
    lJSONParam.S['msgbody'] := 'This is the message sent at ' + DateTimeToStr(Now);
    lJSONParam.S['msgbodyhtml'] := 'This is the HTML message sent at ' + DateTimeToStr(Now);
    lJSONParam.S['msgsubject'] := '[DMS EMAIL CLIENT TEST] This is the subject';
    lJSONParam.S['msgtolist'] := 'larry@google.com,sergey@google.com,timothy@apple.com';
    lJSONParam.S['msgcclist'] := ''; //optional
    lJSONParam.S['msgbcclist'] := 'larry@oracle.com'; //optional
    lJSONParam.S['msgreplytolist'] := '"Spidey" <pparker@email.com>'; //optional
    lReq.Params.Add(lJSONParam);
  except
    lJSONParam.Free;
    raise;
  end;
  lResp := fRPCExecutor.ExecuteRequest(lReq);
  ShowMessage('Message queued with messageid = ' + lResp.ResultAsJSONObject.I['messageid'].ToString);
Retrieve a message by id
PARAMS
token: A valid token
messageid: The id of the message to retrieve
RETURNS
obj: The retrieved message
Raises an exception: if the message doesn't exist
REQUIRED ROLES
If `sender` the user can retrieve only its messages
If `admin` or `monitor` the user can retrieve all the messages
import dmsproxy
proxy = dmsproxy.DMSProxy("https://localhost:443/emailrpc")
proxy.login("user_sender", "pwd1")
message = proxy.get_message_by_id(472)
print(message)
The output is shown below
{
  "msgbody": "This is a text body",
  "msgbodyhtml": "This is a <b>html</b> body",
  "msgnote": "",
  "msgfromaddress": "peter.parker79@libero.it",
  "smtphost": "smtp.libero.it",
  "smtpport": 465,
  "smtpusername": "peter.parker79@libero.it",
  "smtppassword": "<hidden>",
  "smtpusessl": True,
  "smtpsslversion": "TLSv1_1",
  "id": 472,
  "senderuserid": 1,
  "owneruserid": 1,
  "msgtolist": "d.teti@bittime.it,daniele.teti@gmail.com",
  "msgcclist": "",
  "msgbcclist": "",
  "msgsubject": "Here's the files you need",
  "status": "SENT",
  "createdat": "2019-01-09T12:07:13.853Z",
  "sentat": "2019-01-09T12:07:19.281Z",
  "sendnotbeforeof": None,
  "retrycount": 0,
  "lasterror": "",
  "istest": False
}
Deletes a message by id
PARAMS
token: A valid token
messageid: The id of the message to delete
RETURNS
none
Raises an exception: if the message doesn't exist
REQUIRED ROLES
If `sender` the user can retrieve delete its non `SENT` messages
If `admin` the user can delete any message in any state
import dmsproxy
proxy = dmsproxy.DMSProxy("https://localhost:443/emailrpc")
proxy.login("user_sender", "pwd1")
proxy.delete_message(472)
Retrieve a message for a user
PARAMS
token: A valid token
username: The username of the messages
RETURNS
items: A list of messages
Raises an exception: if the message doesn't exist
REQUIRED ROLES
admin or monitor
import dmsproxy
proxy: dmsproxy.DMSProxy = dmsproxy.DMSProxy("https://localhost:443/emailrpc")
proxy.login("user_monitor", "pwd1")
messages = proxy.get_messages_by_username("user_sender")
print(messages)
The output is shown below
[
  {
    "msgbody": "hello body",
    "msgbodyhtml": "This is a <b>html</b> body",
    "msgnote": "",
    "msgfromaddress": "d.teti@bittime.it",
    "smtphost": "smtp.gmail.com",
    "smtpport": 587,
    "smtpusername": "d.teti@bittime.it",
    "smtppassword": "<hidden>",
    "smtpusessl": True,
    "smtpsslversion": "TLSv1",
    "id": 380,
    "senderuserid": 1,
    "owneruserid": 1,
    "msgtolist": "d.teti@bittime.it",
    "msgcclist": "",
    "msgbcclist": "",
    "msgsubject": "This is the subject #1",
    "status": "SENT",
    "createdat": "2018-01-04T16:40:33.832Z",
    "sentat": "2019-01-04T16:41:02.060Z",
    "sendnotbeforeof": "2018-01-04T16:40:32.740Z",
    "retrycount": 0,
    "lasterror": "",
    "istest": False
  },
  "...other json objects..."
]
Retrieve messages by status
PARAMS
token: A valid token
statuslist: A json array containing statuses (e.g. ['TO_SEND','SENT'])
RETURNS
items: A list of messages
Raises an exception: if the statuses are not valid
REQUIRED ROLES
admin or monitor
var
  lReq: IJSONRPCRequest;
  lResp: IJSONRPCResponse;
  lJSONParam: TJsonArray;
begin
  lReq := TJSONRPCRequest.Create(1234, 'getmessagesbystatus');
  lReq.Params.Add(Token);
  lJSONParam := TJsonArray.Create;
  try
    lJSONParam.Add('ERROR');
    lJSONParam.Add('TO_SEND');
    // lJSONParam.Add('SENT');
    lJSONParam.Add('NOT_COMPLETED');
    lReq.Params.Add(lJSONParam);
  except
    lJSONParam.Free;
    raise;
  end;
  lResp := fRPCExecutor.ExecuteRequest(lReq);
  //mtMessages is a TFDMemTable
  mtMessages.Close;
  mtMessages.Open;
  mtMessages.LoadFromJSONArray(lResp.ResultAsJSONArray);
import dmsproxy
proxy: dmsproxy.DMSProxy = dmsproxy.DMSProxy("https://localhost:443/emailrpc")
proxy.login("user_monitor", "pwd1")
messages = proxy.get_messages_by_status(['TO_SEND','SENT'])
print(messages)
The output is shown below
[
  {
    msgbody: "This is a text body",
    msgbodyhtml: "This is a <b>html</b> body",
    msgnote: "",
    msgfromaddress: "d.teti@bittime.it",
    smtphost: "smtp.gmail.com",
    smtpport: 587,
    smtpusername: "d.teti@bittime.it",
    smtppassword: "",
    smtpusessl: True,
    smtpsslversion: "TLSv1",
    id: 380,
    senderuserid: 1,
    owneruserid: 1,
    msgtolist: "d.teti@bittime.it",
    msgcclist: "",
    msgbcclist: "",
    msgsubject: "This is the subject #1",
    status: "SENT",
    createdat: "2019-01-04T16:40:33.832Z",
    sentat: "2019-01-04T16:41:02.060Z",
    sendnotbeforeof: "2019-01-04T16:40:32.740Z",
    retrycount: 0,
    lasterror: "",
    istest: False,
  },
  "...other json objects...",
];
Create message with the abilities to contains attachments, into the messages queue.
The message must be completed using completemessage before to be enqueued in the message queue. If attachments are needed, issue a call to addattachmenttomessage for each attachment.
PARAMS
token: A valid token
obj: A json object with the following properties:
     - msg_to_list: comma separated email address
     - msg_cc_list: comma separated email address
     - msg_bcc_list: comma separated email address
     - msg_subject: the subject of the email
     - is_test: if true the email is not actually sent, used for debug (optional, default false)
     - msg_body: the textual body of the email (optional, default empty)
     - msg_body_html: the html body of the email (optional, default empty)
     - msg_note: note for the others user, doesn't affect the sent email (optional, default empty)
     - send_not_before_of: do not send the message before this timestamp (iso format)
RETURNS
messageid: how the message is identified by the system
REQUIRED ROLES
sender
var
  lReq: IJSONRPCRequest;
  lResp: IJSONRPCResponse;
  lJSONParam: TJsonObject;
begin
  lReq := TJSONRPCRequest.Create(1234, 'createmessage');
  lReq.Params.Add(Token);
  lJSONParam := TJsonObject.Create;
  try
    lJSONParam.S['msgbody'] := 'This is the message sent at ' + DateTimeToStr(Now);
    lJSONParam.S['msgbodyhtml'] := 'This is the HTML message sent at ' + DateTimeToStr(Now);
    lJSONParam.S['msgsubject'] := '[DMS EMAIL CLIENT TEST] This is the subject';
    lJSONParam.S['msgtolist'] := 'larry@google.com,sergey@google.com,timothy@apple.com';
    lJSONParam.S['msgcclist'] := '';
    lJSONParam.S['msgbcclist'] := 'larry@oracle.com';
    lReq.Params.Add(lJSONParam);
  except
    lJSONParam.Free;
    raise;
  end;
  lResp := fRPCExecutor.ExecuteRequest(lReq);
  ShowMessage('Message queued with messageid = ' + lResp.ResultAsJSONObject.I['messageid'].ToString);
Inform the system that a message created with createmessage is ready to be sent.
If attachments are needed, issue a call to addattachmenttomessage for each attachment before the call to completemessage.
PARAMS
token: A valid token
messageid: The messageid of the message that must be completed
RETURNS
none
REQUIRED ROLES
sender
See example about addattachmenttomessage
addattachmenttomessage must be called after createmessage and before completemessage for each attachment needed.
PARAMS
token: A valid token
messageid: The messageid to whom the attachment must be added
isrelated: A boolean value. If True means that the attachment is used into the HTML body of the message obj: A json object with the following properties:
     - filename: the name of the file
     - filedata: the contents of the datafile encoded as base64
RETURNS
none
REQUIRED ROLES
sender
var
  lReq: IJSONRPCRequest;
  lResp: IJSONRPCResponse;
  lJSONParam: TJsonObject;
  lMsgID: Integer;
  lAttachment: String;
  lAttachments: TArray<String>;
begin
  // create the message
  lReq := TJSONRPCRequest.Create(1234, 'createmessage');
  lReq.Params.Add(Token);
  lJSONParam := TJsonObject.Create;
  try
    lJSONParam.S['msgbody'] := 'This message has some attachments';
    lJSONParam.S['msgbodyhtml'] := 'This message <span style="color: red">has</span> some attachments';
    lJSONParam.S['msgsubject'] := '[DMS EMAIL CLIENT TEST] This is the subject';
    lJSONParam.S['msgtolist'] := 'bill@microsoft.com';
    lJSONParam.S['msgcclist'] := 'larry@oracle.com,johndoe@gmail.com';
  except
    lJSONParam.Free;
    raise;
  end;
  lReq.Params.Add(lJSONParam);
  lResp := fRPCExecutor.ExecuteRequest(lReq);
  lMsgID := lResp.ResultAsJSONObject.I['messageid'];
  // add all attachments
  lAttachments := ['file1.png', 'file2.pdf'];
  for lAttachment in lAttachments do
  begin
    lReq := TJSONRPCRequest.Create(1234, 'addattachmenttomessage');
    lReq.Params.Add(Token);
    lReq.Params.Add(lMsgID);
    lReq.Params.Add(false); // is not related
    lJSONParam := TJsonObject.Create;
    try
      lJSONParam.S['filename'] := lAttachment;
      lJSONParam.S['filedata'] := TNetEncoding.Base64.EncodeBytesToString(TFile.ReadAllBytes(lAttachment));
      lReq.Params.Add(lJSONParam);
    except
      lJSONParam.Free;
      raise;
    end;
    fRPCExecutor.ExecuteRequest(lReq);
  end;
  // complete the message
  lReq := TJSONRPCRequest.Create(1234, 'completemessage');
  lReq.Params.Add(Token);
  lReq.Params.Add(lResp.ResultAsJSONObject.I['messageid']);
  fRPCExecutor.ExecuteRequest(lReq);
end;
This example uses the built-in python proxy for the DMSContainer email job available in the Python module dmsproxy.py.
import dmsproxy
from pathlib import Path
proxy = dmsproxy.DMSProxy("https://localhost:443/emailrpc")
proxy.login("user_sender", "pwd1")
msg = {
    "msgtolist": "larry@oracle.com",
    "msgbody": "This is a text body",
    "msgbodyhtml": "This is a <b>html</b> body",
    "msgsubject": "Here's the files you need",
    "is_test": False
}
#create the message
message_id = proxy.create_message(**msg)
# add first attachment
att1 = Path(__file__).parent.joinpath('testdata').joinpath('file1.png')
proxy.add_attachment(message_id, str(att1), False)
# add second attachment
att2 = Path(__file__).parent.joinpath('testdata').joinpath('file2.pdf')
proxy.add_attachment(message_id, str(att2), False)
# complete the message
proxy.complete_message(message_id)
print("Message correctly enqueued with messageid: " + str(message_id))
Inform the system that a message created with createmessage is ready to be sent.
If attachments are needed, issue a call to addattachmenttomessage for each attachment before the call to completemessage.
PARAMS
token: A valid token
messageid: The messageid of the message that must be completed
RETURNS
none
REQUIRED ROLES
sender
See example about addattachmenttomessage
Send a bulk message to a list of email addresses. The message can have also a list of attachments. The body and the attachments can be template driven. If the message contains a template (body or attachment) reportdata must contains the data to generate them.
PARAMS
token: A valid token
aMetaMessage: A json object with the following properties:
     - msgsubject: the subject of the email (can contains template tags)
     - istest: if true the email is not actually sent, used for debug (optional, default false)
     - msgbody: the textual body of the email (can contains template tags) (optional, default empty)
     - msgbodyhtml: the html body of the email (can contains template tags) (optional, default empty)
     - msgnote: note for the others user, doesn't affect the sent email (optional, default empty)
     - attachments: json array of "attachment" json object. Each attachment has the following properties
         - filename: the filename shown to the user (can contains template tags)
         - filedata: the contents of the file. If `is_template` is `true` the filedata **must** be a docx file
         - is_template: boolean value. If true the `filedata` must be a docx file and the attached file will be a PDF.
aBulkMessagesData: A json object with the following properties:
     - meta: ajsonobject containing data shared for all the templates. No specific format is enforced.
     - recipients: a json array which contains the recipents data used for each message. Will be generated one message for each `recipient`.  Each item contains the following properties:
         - msgtolist: comma separated email address
         - msgcclist: comma separated email address
         - msgbcclist: comma separated email address
         - refid: the reference id used to identify the return; usually is the primary key of the database table which should track the sent messages.
     - items: a json array which contains the data used for each message. items can be empty or zero length, but if it exists then must be of the same size of the `recipents` array. Each item can contains any property and those data will be used for each "template" part of the message (subject, body, body_html, attachment etc so on).
RETURNS
messagesid: an array of integer containing the generated messages id.
REQUIRED ROLES
sender
procedure TMainForm.btnSendBulkMessagesClick(Sender: TObject);
var
  lMetaMessage: TJSONObject;
  lMessageData: TJSONObject;
  lRecipient: TJSONObject;
  lItem: TJSONObject;
  lJObj: TJSONObject;
begin
  /// Let's prepare the metadata of the email message
  /// ////////////////////////////////////////////////////////
  lMetaMessage := TJSONObject.Create;
  try
    lMetaMessage.S['msgsubject'] :=
      '[DMSContainer Email TEST] {{meta.title}} - This email is for {{data.nome}} {{data.cognome}}';
    lMetaMessage.S['msgbody'] := '';
    lMetaMessage.S['msgbodyhtml'] := TFile.ReadAllText('template_invito_email_10.html', TEncoding.UTF8);
    lMetaMessage.S['msgnote'] := '';
    lMetaMessage.B['istest'] := false;
    FillWithAttachments(lMetaMessage);
  except
    lMetaMessage.Free;
    raise;
  end;
  /// Let's prepare the actual recipients data
  /// ////////////////////////////////////////////////////////
  lMessageData := TJSONObject.Create;
  try
    /// META
    lMessageData.O['meta'].S['title'] := 'This is the title';
    /// RECIPIENTS
    lRecipient := lMessageData.A['recipients'].AddObject;
    lRecipient.S['msgtolist'] := 'theboss@mydomain.it';
    lRecipient.S['msgcclist'] := 'thebossassistantoffice@mydomain.it';
    lRecipient.S['msgbcclist'] := 'mysecretemail@mydomain.it';
    lRecipient.I['refid'] := 1;
    lRecipient := lMessageData.A['recipients'].AddObject;
    lRecipient.S['msgtolist'] := 'thecustomer@mydomain.it';
    lRecipient.I['refid'] := 2;
    lRecipient := lMessageData.A['recipients'].AddObject;
    lRecipient.S['msgtolist'] := 'thesupplier@mydomain.it';
    lRecipient.I['refid'] := 3;
    /// ITEMS
    lItem := lMessageData.A['items'].AddObject;
    lItem.S['nome'] := 'Daniele';
    lItem.S['cognome'] := 'Teti';
    lItem.S['cerimonia'] := '35° Anniversario Ufficio Affari Vari ed Eventuali';
    lItem.S['luogo_cerimonia'] := 'P.zza 1° Maggio';
    lItem.S['data_cerimonia'] := '1° maggio 2019';
    lItem := lMessageData.A['items'].AddObject;
    lItem.S['nome'] := 'Peter';
    lItem.S['cognome'] := 'Parker';
    lItem.S['cerimonia'] := '35° Anniversario Ufficio Affari Vari ed Eventuali';
    lItem.S['luogo_cerimonia'] := 'P.zza 1° Maggio';
    lItem.S['data_cerimonia'] := '1° maggio 2019';
    lItem := lMessageData.A['items'].AddObject;
    lItem.S['nome'] := 'Sue';
    lItem.S['cognome'] := 'Storm';
    lItem.S['cerimonia'] := '35° Anniversario Ufficio Affari Vari ed Eventuali';
    lItem.S['luogo_cerimonia'] := 'P.zza 1° Maggio';
    lItem.S['data_cerimonia'] := '1° maggio 2019';
  except
    lMessageData.Free;
    raise;
  end;
  lJObj := fEmailRPCProxy.BulkSendMessages(Token, lMetaMessage, lMessageData);
  try
    ShowMessage('Messages queued: ' + lJObj.A['messagesid'].ToJSON(false));
  finally
    lJObj.Free;
  end;
end;
procedure TMainForm.FillWithAttachments(aMetaMessage: TJSONObject);
var
  lJSON: TJSONObject;
begin
  lJSON := aMetaMessage.A['attachments'].AddObject();
  // Parametric attachment template as docx
  lJSON.S['filename'] := 'Invito Mr {{data.cognome}} {{data.nome}}.pdf';
  lJSON.S['filedata'] := FileToBase64String('template_invito_email_10.docx');
  lJSON.B['istemplate'] := true;
  // Non parametric attachment
  lJSON := aMetaMessage.A['attachments'].AddObject();
  lJSON.S['filename'] := 'Dressing Code for Mr {{data.cognome}} {{data.nome}}.pdf';
  lJSON.S['filedata'] := FileToBase64String('non_template_attachment.pdf');
  lJSON.B['istemplate'] := false;
end;