diff --git a/.github/AL-Go-Settings.json b/.github/AL-Go-Settings.json
index 9d995ea2d7..9db124024d 100644
--- a/.github/AL-Go-Settings.json
+++ b/.github/AL-Go-Settings.json
@@ -18,7 +18,8 @@
"CLEAN22",
"CLEAN23",
"CLEAN24",
- "CLEAN25"
+ "CLEAN25",
+ "CLEAN26"
],
"unusedALGoSystemFiles": [
"AddExistingAppOrTestApp.yaml",
diff --git a/src/System Application/App/DotNet Aliases/src/dotnet.al b/src/System Application/App/DotNet Aliases/src/dotnet.al
index 3d6c90fe62..ab644a31b1 100644
--- a/src/System Application/App/DotNet Aliases/src/dotnet.al
+++ b/src/System Application/App/DotNet Aliases/src/dotnet.al
@@ -261,6 +261,16 @@ dotnet
}
}
+ assembly("Microsoft.Dynamics.Nav.AppHTMLSanitizer")
+ {
+ Culture = 'neutral';
+ PublicKeyToken = '31bf3856ad364e35';
+
+ type("Microsoft.Dynamics.Nav.AppHTMLSanitizer.AppHtmlSanitizer"; "AppHtmlSanitizer")
+ {
+ }
+ }
+
assembly("Microsoft.Dynamics.Nav.AzureADGraphClient")
{
type("Microsoft.Dynamics.Nav.AzureADGraphClient.GroupInfoPage"; "GroupInfoPage")
diff --git a/src/System Application/App/Email/src/Account/EmailAccountImpl.Codeunit.al b/src/System Application/App/Email/src/Account/EmailAccountImpl.Codeunit.al
index 63bc7aa1f9..b66b5a4022 100644
--- a/src/System Application/App/Email/src/Account/EmailAccountImpl.Codeunit.al
+++ b/src/System Application/App/Email/src/Account/EmailAccountImpl.Codeunit.al
@@ -29,16 +29,16 @@ codeunit 8889 "Email Account Impl."
var
EmailAccounts: Record "Email Account";
Connector: Enum "Email Connector";
- IEmailConnector: Interface "Email Connector";
+ EmailConnector: Interface "Email Connector";
begin
TempEmailAccount.Reset();
TempEmailAccount.DeleteAll();
foreach Connector in Connector.Ordinals do begin
- IEmailConnector := Connector;
+ EmailConnector := Connector;
EmailAccounts.DeleteAll();
- IEmailConnector.GetAccounts(EmailAccounts);
+ EmailConnector.GetAccounts(EmailAccounts);
if EmailAccounts.FindSet() then
repeat
diff --git a/src/System Application/App/Email/src/Account/EmailAccounts.Page.al b/src/System Application/App/Email/src/Account/EmailAccounts.Page.al
index bfe33cf06a..71fd3a9995 100644
--- a/src/System Application/App/Email/src/Account/EmailAccounts.Page.al
+++ b/src/System Application/App/Email/src/Account/EmailAccounts.Page.al
@@ -387,8 +387,8 @@ page 8887 "Email Accounts"
IsSelected := not IsNullGuid(SelectedAccountId);
EmailAccount.GetAllAccounts(true, Rec); // Refresh the email accounts
- if V2Filter then
- FilterToConnectorv2Accounts(Rec);
+ if V2V3Filter then
+ FilterToConnectorv2v3Accounts(Rec);
EmailScenario.GetDefaultEmailAccount(DefaultEmailAccount); // Refresh the default email account
if IsSelected then begin
@@ -402,7 +402,7 @@ page 8887 "Email Accounts"
CurrPage.Update(false);
end;
- local procedure FilterToConnectorv2Accounts(var EmailAccounts: Record "Email Account")
+ local procedure FilterToConnectorv2v3Accounts(var EmailAccounts: Record "Email Account")
var
IConnector: Interface "Email Connector";
begin
@@ -411,7 +411,13 @@ page 8887 "Email Accounts"
repeat
IConnector := EmailAccounts.Connector;
- if not (IConnector is "Email Connector v2") then
+#if not CLEAN26
+#pragma warning disable AL0432
+ if not (IConnector is "Email Connector v2") and not (IConnector is "Email Connector v3") then
+#pragma warning restore AL0432
+#else
+ if not (IConnector is "Email Connector v3") then
+#endif
EmailAccounts.Delete();
until EmailAccounts.Next() = 0;
end;
@@ -457,12 +463,24 @@ page 8887 "Email Accounts"
end;
///
- /// Filters the email accounts to only show accounts that are using the Email Connector v2.
+ /// Filters the email accounts to only show accounts that are using the Email Connector v2 or v3.
///
/// True to filter the email accounts, false to show all email accounts
- procedure FilterConnectorV2Accounts(Filter: Boolean)
+#if not CLEAN26
+ [Obsolete('Replaced by FilterConnectorV3Accounts. In addition, this function now returns both v2 and v3 accounts.', '26.0')]
+ procedure FilterConnectorV2Accounts(UseFilter: Boolean)
begin
- V2Filter := Filter;
+ V2V3Filter := UseFilter;
+ end;
+#endif
+
+ ///
+ /// Filters the email accounts to only show accounts that are using the Email Connector v2 or v3.
+ ///
+ /// True to filter the email accounts, false to show all email accounts
+ procedure FilterConnectorV3Accounts(UseFilter: Boolean)
+ begin
+ V2V3Filter := UseFilter;
end;
var
@@ -477,6 +495,6 @@ page 8887 "Email Accounts"
ShowLogo: Boolean;
IsLookupMode: Boolean;
HasEmailAccount: Boolean;
- V2Filter: Boolean;
+ V2V3Filter: Boolean;
EmailConnectorHasBeenUninstalledMsg: Label 'The selected email extension has been uninstalled. To view information about the email account, you must reinstall the extension.';
}
\ No newline at end of file
diff --git a/src/System Application/App/Email/src/Connector/DefaultEmailConnectorv2.Codeunit.al b/src/System Application/App/Email/src/Connector/DefaultEmailConnectorv2.Codeunit.al
index 9be71709cb..1a12853797 100644
--- a/src/System Application/App/Email/src/Connector/DefaultEmailConnectorv2.Codeunit.al
+++ b/src/System Application/App/Email/src/Connector/DefaultEmailConnectorv2.Codeunit.al
@@ -8,8 +8,15 @@ namespace System.Email;
///
/// This is the default implementation of the Email Connector v2 interface which adds the reply, retrievial of emails and marking them as read functionalities.
///
-codeunit 8998 "Default Email Connector v2" implements "Email Connector v2"
+#if not CLEAN26
+#pragma warning disable AL0432
+codeunit 8998 "Default Email Connector v2" implements "Email Connector v2", "Email Connector v3"
+#pragma warning restore AL0432
+#else
+codeunit 8998 "Default Email Connector v2" implements "Email Connector v3"
+#endif
{
+
procedure Send(EmailMessage: Codeunit "Email Message"; AccountId: Guid)
begin
@@ -50,10 +57,18 @@ codeunit 8998 "Default Email Connector v2" implements "Email Connector v2"
end;
+#if not CLEAN26
+ [Obsolete('Replaced by RetrieveEmails with an additional Filters parameter of type Record "Email Retrieval Filters".', '26.0')]
procedure RetrieveEmails(AccountId: Guid; var EmailInbox: Record "Email Inbox")
begin
end;
+#endif
+
+ procedure RetrieveEmails(AccountId: Guid; var EmailInbox: Record "Email Inbox"; var Filters: Record "Email Retrieval Filters" temporary)
+ begin
+
+ end;
procedure MarkAsRead(AccountId: Guid; ExternalId: Text)
begin
diff --git a/src/System Application/App/Email/src/Connector/EmailConnector.Enum.al b/src/System Application/App/Email/src/Connector/EmailConnector.Enum.al
index e7b91df374..e44699a614 100644
--- a/src/System Application/App/Email/src/Connector/EmailConnector.Enum.al
+++ b/src/System Application/App/Email/src/Connector/EmailConnector.Enum.al
@@ -8,9 +8,18 @@ namespace System.Email;
///
/// Enum that holds all of the available email connectors.
///
-enum 8889 "Email Connector" implements "Email Connector", "Email Connector v2", "Default Email Rate Limit"
+#if not CLEAN26
+#pragma warning disable AL0432
+enum 8889 "Email Connector" implements "Email Connector", "Email Connector v2", "Email Connector v3", "Default Email Rate Limit"
+#pragma warning restore AL0432
+#else
+enum 8889 "Email Connector" implements "Email Connector", "Email Connector v3", "Default Email Rate Limit"
+#endif
{
Extensible = true;
DefaultImplementation = "Default Email Rate Limit" = "Default Email Rate Limit",
- "Email Connector v2" = "Default Email Connector v2";
+#if not CLEAN26
+ "Email Connector v2" = "Default Email Connector v2",
+#endif
+ "Email Connector v3" = "Default Email Connector v2";
}
\ No newline at end of file
diff --git a/src/System Application/App/Email/src/Connector/EmailConnectorv2.Interface.al b/src/System Application/App/Email/src/Connector/EmailConnectorv2.Interface.al
index 20f36643f5..73fa9a93bd 100644
--- a/src/System Application/App/Email/src/Connector/EmailConnectorv2.Interface.al
+++ b/src/System Application/App/Email/src/Connector/EmailConnectorv2.Interface.al
@@ -1,3 +1,4 @@
+#if not CLEAN26
// ------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
@@ -10,6 +11,10 @@ namespace System.Email;
///
interface "Email Connector v2" extends "Email Connector"
{
+ ObsoleteReason = 'Replaced by "Email Connector v3" which adds filtering capability for retrieval of emails';
+ ObsoleteState = Pending;
+ ObsoleteTag = '26.0';
+
///
/// Reply to an e-mail using the provided account.
///
@@ -30,4 +35,5 @@ interface "Email Connector v2" extends "Email Connector"
/// The email account ID.
/// The external ID of the email.
procedure MarkAsRead(AccountId: Guid; ExternalId: Text);
-}
\ No newline at end of file
+}
+#endif
\ No newline at end of file
diff --git a/src/System Application/App/Email/src/Connector/EmailConnectorv3.Interface.al b/src/System Application/App/Email/src/Connector/EmailConnectorv3.Interface.al
new file mode 100644
index 0000000000..3457e2edb0
--- /dev/null
+++ b/src/System Application/App/Email/src/Connector/EmailConnectorv3.Interface.al
@@ -0,0 +1,34 @@
+// ------------------------------------------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+// ------------------------------------------------------------------------------------------------
+
+namespace System.Email;
+
+///
+/// An e-mail connector interface enhances the "Email Connector" with reading, replying to e-mails and marking emails as read.
+///
+interface "Email Connector v3" extends "Email Connector"
+{
+ ///
+ /// Reply to an e-mail using the provided account.
+ ///
+ /// The email message that is to be sent out.
+ /// The email account ID which is used to send out the email.
+ procedure Reply(var EmailMessage: Codeunit "Email Message"; AccountId: Guid);
+
+ ///
+ /// Read e-mails from the provided account.
+ ///
+ /// The email account ID which is used to send out the email.
+ /// The email inbox record that will store the emails.
+ /// Filters to be used when retrieving emails.
+ procedure RetrieveEmails(AccountId: Guid; var EmailInbox: Record "Email Inbox"; var Filters: Record "Email Retrieval Filters" temporary);
+
+ ///
+ /// Mark an e-mail as read in the provided account.
+ ///
+ /// The email account ID.
+ /// The external ID of the email.
+ procedure MarkAsRead(AccountId: Guid; ExternalId: Text);
+}
\ No newline at end of file
diff --git a/src/System Application/App/Email/src/Email/Email.Codeunit.al b/src/System Application/App/Email/src/Email/Email.Codeunit.al
index 6455872e7a..8968910823 100644
--- a/src/System Application/App/Email/src/Email/Email.Codeunit.al
+++ b/src/System Application/App/Email/src/Email/Email.Codeunit.al
@@ -197,7 +197,7 @@ codeunit 8901 Email
#endregion
#region Reply
-
+#if not CLEAN26
///
/// Sends a reply to an external message id in the foreground.
///
@@ -206,9 +206,10 @@ codeunit 8901 Email
/// The ID of the email account to use for sending the email.
/// The email connector to use for sending the email.
/// True if sent
+ [Obsolete('Replaced by Reply without the ExternalId parameter. ExternalId is not used and is contained in the EmailMessage parameter.', '26.0')]
procedure Reply(EmailMessage: Codeunit "Email Message"; ExternalId: Text; EmailAccountId: Guid; EmailConnector: Enum "Email Connector"): Boolean
begin
- exit(EmailImpl.Reply(EmailMessage, ExternalId, EmailAccountId, EmailConnector));
+ exit(EmailImpl.Reply(EmailMessage, EmailAccountId, EmailConnector));
end;
///
@@ -219,9 +220,10 @@ codeunit 8901 Email
/// The ID of the email account to use for sending the email.
/// The email connector to use for sending the email.
/// True if sent
+ [Obsolete('Replaced by ReplyAll without the ExternalId parameter. ExternalId is not used and is contained in the EmailMessage parameter.', '26.0')]
procedure ReplyAll(EmailMessage: Codeunit "Email Message"; ExternalId: Text; EmailAccountId: Guid; EmailConnector: Enum "Email Connector"): Boolean
begin
- exit(EmailImpl.ReplyAll(EmailMessage, ExternalId, EmailAccountId, EmailConnector));
+ exit(EmailImpl.ReplyAll(EmailMessage, EmailAccountId, EmailConnector));
end;
///
@@ -232,9 +234,10 @@ codeunit 8901 Email
/// The ID of the email account to use for sending the email.
/// The email connector to use for sending the email.
/// The email outbox which is set up for sending in the background.
+ [Obsolete('Replaced by EnqueueReply without the ExternalId parameter. ExternalId is not used and is contained in the EmailMessage parameter.', '26.0')]
procedure EnqueueReply(EmailMessage: Codeunit "Email Message"; ExternalId: Text; EmailAccountId: Guid; EmailConnector: Enum "Email Connector"; var EmailOutbox: Record "Email Outbox")
begin
- EmailImpl.Reply(EmailMessage, ExternalId, EmailAccountId, EmailConnector, EmailOutbox);
+ EmailImpl.Reply(EmailMessage, EmailAccountId, EmailConnector, EmailOutbox);
end;
///
@@ -245,25 +248,88 @@ codeunit 8901 Email
/// The ID of the email account to use for sending the email.
/// The email connector to use for sending the email.
/// The email outbox which is set up for sending in the background.
+ [Obsolete('Replaced by EnqueueReplyAll without the ExternalId parameter. ExternalId is not used and is contained in the EmailMessage parameter.', '26.0')]
procedure EnqueueReplyAll(EmailMessage: Codeunit "Email Message"; ExternalId: Text; EmailAccountId: Guid; EmailConnector: Enum "Email Connector"; var EmailOutbox: Record "Email Outbox")
begin
- EmailImpl.ReplyAll(EmailMessage, ExternalId, EmailAccountId, EmailConnector, EmailOutbox);
+ EmailImpl.ReplyAll(EmailMessage, EmailAccountId, EmailConnector, EmailOutbox);
+ end;
+#endif
+
+ ///
+ /// Sends a reply to an external message id in the foreground.
+ ///
+ /// The email message with the details of the recipients and reply to be added.
+ /// The ID of the email account to use for sending the email.
+ /// The email connector to use for sending the email.
+ /// True if sent
+ procedure Reply(EmailMessage: Codeunit "Email Message"; EmailAccountId: Guid; EmailConnector: Enum "Email Connector"): Boolean
+ begin
+ exit(EmailImpl.Reply(EmailMessage, EmailAccountId, EmailConnector));
+ end;
+
+ ///
+ /// Sends a reply to an external message id to all recipients on that email in the foreground.
+ ///
+ /// The email message with the details of the recipients and reply to be added.
+ /// The ID of the email account to use for sending the email.
+ /// The email connector to use for sending the email.
+ /// True if sent
+ procedure ReplyAll(EmailMessage: Codeunit "Email Message"; EmailAccountId: Guid; EmailConnector: Enum "Email Connector"): Boolean
+ begin
+ exit(EmailImpl.ReplyAll(EmailMessage, EmailAccountId, EmailConnector));
+ end;
+
+ ///
+ /// Sends a reply to an external message id in the background.
+ ///
+ /// The email message with the details of the recipients and reply to be added.
+ /// The ID of the email account to use for sending the email.
+ /// The email connector to use for sending the email.
+ /// The email outbox which is set up for sending in the background.
+ procedure EnqueueReply(EmailMessage: Codeunit "Email Message"; EmailAccountId: Guid; EmailConnector: Enum "Email Connector"; var EmailOutbox: Record "Email Outbox")
+ begin
+ EmailImpl.Reply(EmailMessage, EmailAccountId, EmailConnector, EmailOutbox);
+ end;
+
+ ///
+ /// Sends a reply to an external message id to all recipients on that email in the foreground.
+ ///
+ /// The email message with the details of the recipients and reply to be added.
+ /// The ID of the email account to use for sending the email.
+ /// The email connector to use for sending the email.
+ /// The email outbox which is set up for sending in the background.
+ procedure EnqueueReplyAll(EmailMessage: Codeunit "Email Message"; EmailAccountId: Guid; EmailConnector: Enum "Email Connector"; var EmailOutbox: Record "Email Outbox")
+ begin
+ EmailImpl.ReplyAll(EmailMessage, EmailAccountId, EmailConnector, EmailOutbox);
end;
#endregion
#region RetrieveEmails
-
+#if not CLEAN26
///
/// Retrieves emails from the email account.
///
/// The ID of the email account to use for sending the email.
/// The email connector to use for sending the email.
/// The return record of all new emails that were retrieved.
+ [Obsolete('Replaced by RetrieveEmails with an additional Filters parameter of type Record "Email Retrieval Filters".', '26.0')]
procedure RetrieveEmails(EmailAccountId: Guid; EmailConnector: Enum "Email Connector"; var EmailInbox: Record "Email Inbox")
begin
EmailImpl.RetrieveEmails(EmailAccountId, EmailConnector, EmailInbox);
end;
+#endif
+ ///
+ /// Retrieves emails from the email account.
+ ///
+ /// The ID of the email account to use for sending the email.
+ /// The email connector to use for sending the email.
+ /// The return record of all new emails that were retrieved.
+ /// Filters to be used when retrieving emails.
+ procedure RetrieveEmails(EmailAccountId: Guid; EmailConnector: Enum "Email Connector"; var EmailInbox: Record "Email Inbox"; var Filters: Record "Email Retrieval Filters" temporary)
+ begin
+ EmailImpl.RetrieveEmails(EmailAccountId, EmailConnector, EmailInbox, Filters);
+ end;
#endregion
diff --git a/src/System Application/App/Email/src/Email/EmailImpl.Codeunit.al b/src/System Application/App/Email/src/Email/EmailImpl.Codeunit.al
index e08ce2c8a6..c181dfe49f 100644
--- a/src/System Application/App/Email/src/Email/EmailImpl.Codeunit.al
+++ b/src/System Application/App/Email/src/Email/EmailImpl.Codeunit.al
@@ -125,31 +125,31 @@ codeunit 8900 "Email Impl"
exit(Send(EmailMessage, EmailAccountId, EmailConnector, false, CurrentDateTime(), EmailOutbox));
end;
- procedure Reply(EmailMessage: Codeunit "Email Message"; ExternalId: Text; EmailAccountId: Guid; EmailConnector: Enum "Email Connector"): Boolean
+ procedure Reply(EmailMessage: Codeunit "Email Message"; EmailAccountId: Guid; EmailConnector: Enum "Email Connector"): Boolean
var
EmailOutbox: Record "Email Outbox";
begin
- exit(Reply(EmailMessage, ExternalId, EmailAccountId, EmailConnector, EmailOutbox, CurrentDateTime(), false, false));
+ exit(Reply(EmailMessage, EmailAccountId, EmailConnector, EmailOutbox, CurrentDateTime(), false, false));
end;
- procedure ReplyAll(EmailMessage: Codeunit "Email Message"; ExternalId: Text; EmailAccountId: Guid; EmailConnector: Enum "Email Connector"): Boolean
+ procedure ReplyAll(EmailMessage: Codeunit "Email Message"; EmailAccountId: Guid; EmailConnector: Enum "Email Connector"): Boolean
var
EmailOutbox: Record "Email Outbox";
begin
- exit(Reply(EmailMessage, ExternalId, EmailAccountId, EmailConnector, EmailOutbox, CurrentDateTime(), false, true));
+ exit(Reply(EmailMessage, EmailAccountId, EmailConnector, EmailOutbox, CurrentDateTime(), false, true));
end;
- procedure Reply(EmailMessage: Codeunit "Email Message"; ExternalId: Text; EmailAccountId: Guid; EmailConnector: Enum "Email Connector"; var EmailOutbox: Record "Email Outbox")
+ procedure Reply(EmailMessage: Codeunit "Email Message"; EmailAccountId: Guid; EmailConnector: Enum "Email Connector"; var EmailOutbox: Record "Email Outbox")
begin
- Reply(EmailMessage, ExternalId, EmailAccountId, EmailConnector, EmailOutbox, CurrentDateTime(), true, false);
+ Reply(EmailMessage, EmailAccountId, EmailConnector, EmailOutbox, CurrentDateTime(), true, false);
end;
- procedure ReplyAll(EmailMessage: Codeunit "Email Message"; ExternalId: Text; EmailAccountId: Guid; EmailConnector: Enum "Email Connector"; var EmailOutbox: Record "Email Outbox")
+ procedure ReplyAll(EmailMessage: Codeunit "Email Message"; EmailAccountId: Guid; EmailConnector: Enum "Email Connector"; var EmailOutbox: Record "Email Outbox")
begin
- Reply(EmailMessage, ExternalId, EmailAccountId, EmailConnector, EmailOutbox, CurrentDateTime(), true, true);
+ Reply(EmailMessage, EmailAccountId, EmailConnector, EmailOutbox, CurrentDateTime(), true, true);
end;
- procedure Reply(EmailMessage: Codeunit "Email Message"; ExternalId: Text; EmailAccountId: Guid; EmailConnector: Enum "Email Connector"; var EmailOutbox: Record "Email Outbox"; NotBefore: DateTime; InBackground: Boolean; ReplyToAll: Boolean): Boolean
+ procedure Reply(EmailMessage: Codeunit "Email Message"; EmailAccountId: Guid; EmailConnector: Enum "Email Connector"; var EmailOutbox: Record "Email Outbox"; NotBefore: DateTime; InBackground: Boolean; ReplyToAll: Boolean): Boolean
var
EmailAccountRec: Record "Email Account";
CurrentUser: Record User;
@@ -172,6 +172,9 @@ codeunit 8900 "Email Impl"
if GetEmailOutbox(EmailMessage.GetId(), EmailOutbox) and IsOutboxEnqueued(EmailOutbox) then
Error(EmailMessageQueuedErr);
+ if EmailMessage.GetExternalId() = '' then
+ Error(ExternalIdCannotBeEmptyErr);
+
// Get email account
GetEmailAccount(EmailAccountId, EmailConnector, EmailAccountRec);
@@ -199,17 +202,41 @@ codeunit 8900 "Email Impl"
procedure RetrieveEmails(EmailAccountId: Guid; Connector: Enum "Email Connector"; var EmailInbox: Record "Email Inbox")
var
- IEmailConnectorv2: Interface "Email Connector v2";
+ Filters: Record "Email Retrieval Filters";
+ begin
+ Filters.Insert();
+ RetrieveEmails(EmailAccountId, Connector, EmailInbox, Filters);
+ end;
+
+ procedure RetrieveEmails(EmailAccountId: Guid; Connector: Enum "Email Connector"; var EmailInbox: Record "Email Inbox"; var Filters: Record "Email Retrieval Filters" temporary)
+ var
+#if not CLEAN26
+#pragma warning disable AL0432
+ EmailConnectorv2: Interface "Email Connector v2";
+#pragma warning restore AL0432
+#endif
+ EmailConnectorv3: Interface "Email Connector v3";
begin
CheckRequiredPermissions();
- if CheckAndGetEmailConnectorv2(Connector, IEmailConnectorv2) then begin
+ if CheckAndGetEmailConnectorv3(Connector, EmailConnectorv3) then begin
TelemetryAppsAndPublishers(TelemetryRetrieveEmailsUsedTxt);
- IEmailConnectorv2.RetrieveEmails(EmailAccountId, EmailInbox);
- end else
- Error(EmailConnectorDoesNotSupportRetrievingEmailsErr);
+ EmailConnectorv3.RetrieveEmails(EmailAccountId, EmailInbox, Filters);
+ EmailInbox.MarkedOnly(true);
+ exit;
+ end;
+#if not CLEAN26
+#pragma warning disable AL0432
+ if CheckAndGetEmailConnectorv2(Connector, EmailConnectorv2) then begin
+#pragma warning restore AL0432
+ TelemetryAppsAndPublishers(TelemetryRetrieveEmailsUsedTxt);
+ EmailConnectorv2.RetrieveEmails(EmailAccountId, EmailInbox);
+ EmailInbox.MarkedOnly(true);
+ exit;
+ end;
+#endif
- EmailInbox.MarkedOnly(true);
+ Error(EmailConnectorDoesNotSupportRetrievingEmailsErr);
end;
local procedure TelemetryAppsAndPublishers(Message: Text)
@@ -236,30 +263,59 @@ codeunit 8900 "Email Impl"
procedure MarkAsRead(EmailAccountId: Guid; Connector: Enum "Email Connector"; ExternalId: Text)
var
- IEmailConnectorv2: Interface "Email Connector v2";
+#if not CLEAN26
+#pragma warning disable AL0432
+ EmailConnectorv2: Interface "Email Connector v2";
+#pragma warning restore AL0432
+#endif
+ EmailConnectorv3: Interface "Email Connector v3";
begin
CheckRequiredPermissions();
if ExternalId = '' then
Error(ExternalIdCannotBeEmptyErr);
- if CheckAndGetEmailConnectorv2(Connector, IEmailConnectorv2) then
- IEmailConnectorv2.MarkAsRead(EmailAccountId, ExternalId)
- else
- Error(EmailConnectorDoesNotSupportMarkAsReadErr);
+ if CheckAndGetEmailConnectorv3(Connector, EmailConnectorv3) then begin
+ EmailConnectorv3.MarkAsRead(EmailAccountId, ExternalId);
+ exit;
+ end;
+#if not CLEAN26
+#pragma warning disable AL0432
+ if CheckAndGetEmailConnectorv2(Connector, EmailConnectorv2) then begin
+#pragma warning restore AL0432
+ EmailConnectorv2.MarkAsRead(EmailAccountId, ExternalId);
+ exit;
+ end;
+#endif
+
+ Error(EmailConnectorDoesNotSupportMarkAsReadErr);
end;
procedure CheckReplySupported(Connector: Enum "Email Connector"): Boolean
var
- IEmailConnectorv2: Interface "Email Connector v2";
+#if not CLEAN26
+#pragma warning disable AL0432
+ EmailConnectorv2: Interface "Email Connector v2";
+#pragma warning restore AL0432
+#endif
+ EmailConnectorv3: Interface "Email Connector v3";
begin
- if not CheckAndGetEmailConnectorv2(Connector, IEmailConnectorv2) then
- Error(EmailconnectorDoesNotSupportReplyingErr);
+ if CheckAndGetEmailConnectorv3(Connector, EmailConnectorv3) then
+ exit(true);
+#if not CLEAN26
+#pragma warning disable AL0432
+ if CheckAndGetEmailConnectorv2(Connector, EmailConnectorv2) then
+ exit(true);
+#pragma warning restore AL0432
+#endif
- exit(true);
+ Error(EmailconnectorDoesNotSupportReplyingErr);
end;
-
+#if not CLEAN26
+#pragma warning disable AL0432
+ [Obsolete('Replaced by CheckAndGetEmailConnectorv3.', '26.0')]
procedure CheckAndGetEmailConnectorv2(Connector: Interface "Email Connector"; var Connectorv2: Interface "Email Connector v2"): Boolean
+#pragma warning restore AL0432
begin
if Connector is "Email Connector v2" then begin
Connectorv2 := Connector as "Email Connector v2";
@@ -267,6 +323,16 @@ codeunit 8900 "Email Impl"
end else
exit(false);
end;
+#endif
+
+ procedure CheckAndGetEmailConnectorv3(Connector: Interface "Email Connector"; var Connectorv3: Interface "Email Connector v3"): Boolean
+ begin
+ if Connector is "Email Connector v3" then begin
+ Connectorv3 := Connector as "Email Connector v3";
+ exit(true);
+ end else
+ exit(false);
+ end;
procedure OpenInEditor(EmailMessage: Codeunit "Email Message"; EmailScenario: Enum "Email Scenario"; IsModal: Boolean): Enum "Email Action"
var
diff --git a/src/System Application/App/Email/src/Email/Inbox/EmailInbox.Table.al b/src/System Application/App/Email/src/Email/Inbox/EmailInbox.Table.al
index 4235488296..d9ba46f55f 100644
--- a/src/System Application/App/Email/src/Email/Inbox/EmailInbox.Table.al
+++ b/src/System Application/App/Email/src/Email/Inbox/EmailInbox.Table.al
@@ -76,6 +76,16 @@ table 8886 "Email Inbox"
{
DataClassification = CustomerContent;
}
+
+ field(13; "Is Read"; Boolean)
+ {
+ DataClassification = CustomerContent;
+ }
+
+ field(14; "Is Draft"; Boolean)
+ {
+ DataClassification = CustomerContent;
+ }
}
keys
diff --git a/src/System Application/App/Email/src/Email/Inbox/EmailRetrievalFilters.Table.al b/src/System Application/App/Email/src/Email/Inbox/EmailRetrievalFilters.Table.al
new file mode 100644
index 0000000000..7f17da78b6
--- /dev/null
+++ b/src/System Application/App/Email/src/Email/Inbox/EmailRetrievalFilters.Table.al
@@ -0,0 +1,65 @@
+// ------------------------------------------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+// ------------------------------------------------------------------------------------------------
+
+namespace System.Email;
+
+/// Holds information about the filters for retrieving emails.
+table 8885 "Email Retrieval Filters"
+{
+ Access = Public;
+ TableType = Temporary;
+ DataClassification = SystemMetadata;
+ InherentEntitlements = RIMDX;
+ InherentPermissions = RIMDX;
+
+ fields
+ {
+ field(1; Id; Integer)
+ {
+ AutoIncrement = true;
+ }
+
+ field(2; "Load Attachments"; Boolean)
+ {
+ Caption = 'Load Attachments';
+ }
+
+ field(3; "Unread Emails"; Boolean)
+ {
+ Caption = 'Unread Emails';
+ }
+
+ field(4; "Draft Emails"; Boolean)
+ {
+ Caption = 'Draft Emails';
+ }
+
+ field(5; "Max No. of Emails"; Integer)
+ {
+ InitValue = 20;
+ Caption = 'Max No. of Emails';
+ }
+
+ field(6; "Body Type"; Option)
+ {
+ OptionMembers = "HTML","Text";
+ InitValue = "HTML";
+ Caption = 'Body Type';
+ }
+
+ field(7; "Earliest Email"; DateTime)
+ {
+ Caption = 'Earliest Email';
+ }
+ }
+
+ keys
+ {
+ key(PK; Id)
+ {
+ Clustered = true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/System Application/App/Email/src/Email/SendEmail.Codeunit.al b/src/System Application/App/Email/src/Email/SendEmail.Codeunit.al
index 08fd191271..c236de3940 100644
--- a/src/System Application/App/Email/src/Email/SendEmail.Codeunit.al
+++ b/src/System Application/App/Email/src/Email/SendEmail.Codeunit.al
@@ -16,22 +16,33 @@ codeunit 8890 "Send Email"
var
EmailMessage: Codeunit "Email Message";
EmailImpl: Codeunit "Email Impl";
- IEmailConnector: Interface "Email Connector";
- IEmailConnectorv2: Interface "Email Connector v2";
+ EmailConnector: Interface "Email Connector";
+#if not CLEAN26
+#pragma warning disable AL0432
+ EmailConnectorv2: Interface "Email Connector v2";
+#pragma warning restore AL0432
+#endif
+ EmailConnectorv3: Interface "Email Connector v3";
begin
EmailMessage.Get(Rec.Id);
if EmailMessage.GetExternalId() <> '' then begin
- IEmailConnector := EmailConnector;
- if EmailImpl.CheckAndGetEmailConnectorv2(IEmailConnector, IEmailConnectorv2) then
- IEmailConnectorv2.Reply(EmailMessage, AccountId);
+ EmailConnector := GlobalEmailConnector;
+#if not CLEAN26
+#pragma warning disable AL0432
+ if EmailImpl.CheckAndGetEmailConnectorv2(EmailConnector, EmailConnectorv2) then
+#pragma warning restore AL0432
+ EmailConnectorv2.Reply(EmailMessage, AccountId);
+#endif
+ if EmailImpl.CheckAndGetEmailConnectorv3(EmailConnector, EmailConnectorv3) then
+ EmailConnectorv3.Reply(EmailMessage, AccountId);
end else
- EmailConnector.Send(EmailMessage, AccountId);
+ GlobalEmailConnector.Send(EmailMessage, AccountId);
end;
procedure SetConnector(NewEmailConnector: Interface "Email Connector")
begin
- EmailConnector := NewEmailConnector;
+ GlobalEmailConnector := NewEmailConnector;
end;
procedure SetAccount(NewAccountId: Guid)
@@ -40,6 +51,6 @@ codeunit 8890 "Send Email"
end;
var
- EmailConnector: Interface "Email Connector";
+ GlobalEmailConnector: Interface "Email Connector";
AccountId: Guid;
}
\ No newline at end of file
diff --git a/src/System Application/App/Email/src/Message/EmailMessage.Codeunit.al b/src/System Application/App/Email/src/Message/EmailMessage.Codeunit.al
index 01c836d4c8..3ae7967701 100644
--- a/src/System Application/App/Email/src/Message/EmailMessage.Codeunit.al
+++ b/src/System Application/App/Email/src/Message/EmailMessage.Codeunit.al
@@ -35,6 +35,21 @@ codeunit 8904 "Email Message"
EmailMessageImpl.Create(ToRecipients, Subject, Body, HtmlFormatted);
end;
+ ///
+ /// Creates the email with recipients, subject, and body.
+ ///
+ /// The recipient(s) of the email. A string containing the email addresses of the recipients separated by semicolon.
+ /// The subject of the email.
+ /// The body of the email.
+ /// Whether the body is HTML formatted.
+ /// If the body is of HTML formatting, most of it will be sanitized. Keeping only tags and no styling.
+ /// Sanitize is only applicable if the body is HTML formatted. It also helps prevent potential email messages from hiding images and text from the user.
+ procedure Create(ToRecipients: Text; Subject: Text; Body: Text; HtmlFormatted: Boolean; Sanitize: Boolean)
+ begin
+ EmailMessageImpl.Create(ToRecipients, Subject, Body, HtmlFormatted, Sanitize);
+ end;
+
+
///
/// Creates the email with recipients, subject, and body.
///
@@ -43,8 +58,11 @@ codeunit 8904 "Email Message"
/// The body of the email
/// Whether the body is HTML formatted
procedure Create(ToRecipients: List of [Text]; Subject: Text; Body: Text; HtmlFormatted: Boolean)
+ var
+ CCRecipients: List of [Text];
+ BCCRecipients: List of [Text];
begin
- EmailMessageImpl.Create(ToRecipients, Subject, Body, HtmlFormatted);
+ EmailMessageImpl.Create(ToRecipients, Subject, Body, HtmlFormatted, CCRecipients, BCCRecipients, false);
end;
///
@@ -58,7 +76,7 @@ codeunit 8904 "Email Message"
/// TThe BCC recipient(s) of the email. A list of email addresses that will be listed as BCC.
procedure Create(ToRecipients: List of [Text]; Subject: Text; Body: Text; HtmlFormatted: Boolean; CCRecipients: List of [Text]; BCCRecipients: List of [Text])
begin
- EmailMessageImpl.Create(ToRecipients, Subject, Body, HtmlFormatted, CCRecipients, BCCRecipients);
+ EmailMessageImpl.Create(ToRecipients, Subject, Body, HtmlFormatted, CCRecipients, BCCRecipients, false);
end;
///
@@ -83,8 +101,11 @@ codeunit 8904 "Email Message"
/// Whether the body is HTML formatted.
/// The external message id to reply to.
procedure CreateReply(ToRecipients: List of [Text]; Subject: Text; Body: Text; HtmlFormatted: Boolean; ExternalId: Text)
+ var
+ CCRecipients: List of [Text];
+ BCCRecipients: List of [Text];
begin
- EmailMessageImpl.CreateReply(ToRecipients, Subject, Body, HtmlFormatted, ExternalId);
+ EmailMessageImpl.CreateReply(ToRecipients, Subject, Body, HtmlFormatted, ExternalId, CCRecipients, BCCRecipients);
end;
///
diff --git a/src/System Application/App/Email/src/Message/EmailMessageImpl.Codeunit.al b/src/System Application/App/Email/src/Message/EmailMessageImpl.Codeunit.al
index 1ceac8f859..9dc5be3522 100644
--- a/src/System Application/App/Email/src/Message/EmailMessageImpl.Codeunit.al
+++ b/src/System Application/App/Email/src/Message/EmailMessageImpl.Codeunit.al
@@ -53,57 +53,50 @@ codeunit 8905 "Email Message Impl."
end;
procedure Create(ToRecipients: Text; Subject: Text; Body: Text; HtmlFormatted: Boolean)
- var
- EmptyList: List of [Text];
begin
-#pragma warning disable AA0205
- Create(EmptyList, Subject, Body, HtmlFormatted);
-#pragma warning restore AA0205
-
- SetRecipients(Enum::"Email Recipient Type"::"To", ToRecipients);
+ Create(ToRecipients, Subject, Body, HtmlFormatted, false);
end;
- procedure Create(Recipients: List of [Text]; Subject: Text; Body: Text; HtmlFormatted: Boolean)
+ procedure Create(ToRecipients: Text; Subject: Text; Body: Text; HtmlFormatted: Boolean; Sanitize: Boolean)
var
- EmptyList: List of [Text];
+ Recipients: List of [Text];
+ CCRecipients: List of [Text];
+ BCCRecipients: List of [Text];
begin
-#pragma warning disable AA0205
- Create(Recipients, Subject, Body, HtmlFormatted, EmptyList, EmptyList);
-#pragma warning restore AA0205
+ Create(Recipients, Subject, Body, HtmlFormatted, CCRecipients, BCCRecipients, Sanitize);
+
+ SetRecipients(Enum::"Email Recipient Type"::"To", ToRecipients);
end;
- procedure Create(Recipients: List of [Text]; Subject: Text; Body: Text; HtmlFormatted: Boolean; CCRecipients: List of [Text]; BCCRecipients: List of [Text])
+ procedure Create(Recipients: List of [Text]; Subject: Text; Body: Text; HtmlFormatted: Boolean; CCRecipients: List of [Text]; BCCRecipients: List of [Text]; Sanitize: Boolean)
begin
InitializeCreation();
- UpdateMessage(Recipients, Subject, Body, HtmlFormatted, '', CCRecipients, BCCRecipients);
+ UpdateMessage(Recipients, Subject, Body, HtmlFormatted, '', CCRecipients, BCCRecipients, Sanitize);
end;
procedure CreateReply(ToRecipients: Text; Subject: Text; Body: Text; HtmlFormatted: Boolean; ExternalId: Text)
var
- EmptyList: List of [Text];
+ Recipients: List of [Text];
+ CCRecipients: List of [Text];
+ BCCRecipients: List of [Text];
begin
- CreateReply(EmptyList, Subject, Body, HtmlFormatted, ExternalId, EmptyList, EmptyList);
+ CreateReply(Recipients, Subject, Body, HtmlFormatted, ExternalId, CCRecipients, BCCRecipients);
SetRecipients(Enum::"Email Recipient Type"::"To", ToRecipients);
end;
- procedure CreateReply(ToRecipients: List of [Text]; Subject: Text; Body: Text; HtmlFormatted: Boolean; ExternalId: Text)
- var
- EmptyList: List of [Text];
+ procedure CreateReply(ToRecipients: List of [Text]; Subject: Text; Body: Text; HtmlFormatted: Boolean; ExternalId: Text; CCRecipients: List of [Text]; BCCRecipients: List of [Text])
begin
- CreateReply(ToRecipients, Subject, Body, HtmlFormatted, ExternalId, EmptyList, EmptyList);
+ InitializeCreation();
+ UpdateMessage(ToRecipients, Subject, Body, HtmlFormatted, ExternalId, CCRecipients, BCCRecipients, false);
end;
procedure CreateReplyAll(Subject: Text; Body: Text; HtmlFormatted: Boolean; ExternalId: Text)
var
- EmptyList: List of [Text];
+ ToRecipients: List of [Text];
+ CCRecipients: List of [Text];
+ BCCRecipients: List of [Text];
begin
- CreateReply(EmptyList, Subject, Body, HtmlFormatted, ExternalId, EmptyList, EmptyList);
- end;
-
- procedure CreateReply(ToRecipients: List of [Text]; Subject: Text; Body: Text; HtmlFormatted: Boolean; ExternalId: Text; CCRecipients: List of [Text]; BCCRecipients: List of [Text])
- begin
- InitializeCreation();
- UpdateMessage(ToRecipients, Subject, Body, HtmlFormatted, ExternalId, CCRecipients, BCCRecipients);
+ CreateReply(ToRecipients, Subject, Body, HtmlFormatted, ExternalId, CCRecipients, BCCRecipients);
end;
local procedure InitializeCreation()
@@ -115,8 +108,11 @@ codeunit 8905 "Email Message Impl."
GlobalEmailMessage.Insert();
end;
- procedure UpdateMessage(ToRecipients: List of [Text]; Subject: Text; Body: Text; HtmlFormatted: Boolean; ExternalId: Text; CCRecipients: List of [Text]; BCCRecipients: List of [Text])
+ procedure UpdateMessage(ToRecipients: List of [Text]; Subject: Text; Body: Text; HtmlFormatted: Boolean; ExternalId: Text; CCRecipients: List of [Text]; BCCRecipients: List of [Text]; Sanitize: Boolean)
begin
+ if HtmlFormatted and Sanitize then
+ Body := SanitizeBody(Body);
+
SetBodyValue(Body);
SetSubjectValue(Subject);
SetBodyHTMLFormattedValue(HtmlFormatted);
@@ -128,6 +124,14 @@ codeunit 8905 "Email Message Impl."
SetRecipients(Enum::"Email Recipient Type"::Bcc, BCCRecipients);
end;
+ local procedure SanitizeBody(Body: Text): Text
+ var
+ AppHTMLSanitizer: DotNet AppHtmlSanitizer;
+ begin
+ AppHTMLSanitizer := AppHTMLSanitizer.AppHtmlSanitizer();
+ exit(AppHTMLSanitizer.SanitizeEmail(Body));
+ end;
+
procedure Modify()
var
EmailMessage: Record "Email Message";
diff --git a/src/System Application/Test Library/Email/app.json b/src/System Application/Test Library/Email/app.json
index 20a3312277..29291181ac 100644
--- a/src/System Application/Test Library/Email/app.json
+++ b/src/System Application/Test Library/Email/app.json
@@ -40,6 +40,10 @@
{
"from": 134694,
"to": 134694
+ },
+ {
+ "from": 134702,
+ "to": 134702
}
],
"contextSensitiveHelpUrl": "https://go.microsoft.com/fwlink/?linkid=2134520",
diff --git a/src/System Application/Test Library/Email/src/TestEmailConnector.EnumExt.al b/src/System Application/Test Library/Email/src/TestEmailConnector.EnumExt.al
index d6810edf0b..b438681ab3 100644
--- a/src/System Application/Test Library/Email/src/TestEmailConnector.EnumExt.al
+++ b/src/System Application/Test Library/Email/src/TestEmailConnector.EnumExt.al
@@ -13,8 +13,14 @@ enumextension 134684 "Test Email Connector" extends "Email Connector"
{
Implementation = "Email Connector" = "Test Email Connector";
}
+#if not CLEAN26
value(134685; "Test Email Connector v2")
{
Implementation = "Email Connector" = "Test Email Connector v2";
}
+#endif
+ value(134686; "Test Email Connector v3")
+ {
+ Implementation = "Email Connector" = "Test Email Connector v3";
+ }
}
\ No newline at end of file
diff --git a/src/System Application/Test Library/Email/src/TestEmailConnectorv2.Codeunit.al b/src/System Application/Test Library/Email/src/TestEmailConnectorv2.Codeunit.al
index 7e2d9dd685..c7602641ad 100644
--- a/src/System Application/Test Library/Email/src/TestEmailConnectorv2.Codeunit.al
+++ b/src/System Application/Test Library/Email/src/TestEmailConnectorv2.Codeunit.al
@@ -1,3 +1,4 @@
+#if not CLEAN26
// ------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
@@ -7,7 +8,9 @@ namespace System.TestLibraries.Email;
using System.Email;
-codeunit 134682 "Test Email Connector v2" implements "Email Connector v2", "Email Connector" // Temporary bug #540622
+#pragma warning disable AL0432
+codeunit 134682 "Test Email Connector v2" implements "Email Connector v2"
+#pragma warning restore AL0432
{
var
@@ -87,4 +90,5 @@ codeunit 134682 "Test Email Connector v2" implements "Email Connector v2", "Emai
if ConnectorMock.FailOnMarkAsRead() then
Error('Failed to mark email as read');
end;
-}
\ No newline at end of file
+}
+#endif
\ No newline at end of file
diff --git a/src/System Application/Test Library/Email/src/TestEmailConnectorv3.Codeunit.al b/src/System Application/Test Library/Email/src/TestEmailConnectorv3.Codeunit.al
new file mode 100644
index 0000000000..20c89be8aa
--- /dev/null
+++ b/src/System Application/Test Library/Email/src/TestEmailConnectorv3.Codeunit.al
@@ -0,0 +1,90 @@
+// ------------------------------------------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+// ------------------------------------------------------------------------------------------------
+
+namespace System.TestLibraries.Email;
+
+using System.Email;
+
+codeunit 134702 "Test Email Connector v3" implements "Email Connector v3"
+{
+
+ var
+ ConnectorMock: Codeunit "Connector Mock";
+
+ procedure Send(EmailMessage: Codeunit "Email Message"; AccountId: Guid)
+ begin
+ ConnectorMock.SetEmailMessageID(EmailMessage.GetId());
+ Commit();
+ if ConnectorMock.FailOnSend() then
+ Error('Failed to send email');
+ end;
+
+ procedure GetAccounts(var Accounts: Record "Email Account")
+ begin
+ ConnectorMock.GetAccounts(Accounts, Enum::"Email Connector"::"Test Email Connector v3");
+ end;
+
+ procedure ShowAccountInformation(AccountId: Guid)
+ begin
+ Message('Showing information for account: %1', AccountId);
+ end;
+
+ procedure RegisterAccount(var EmailAccount: Record "Email Account"): Boolean
+ begin
+ if ConnectorMock.FailOnRegisterAccount() then
+ Error('Failed to register account');
+
+ if ConnectorMock.UnsuccessfulRegister() then
+ exit(false);
+
+ EmailAccount."Account Id" := CreateGuid();
+ EmailAccount."Email Address" := 'Test email address';
+ EmailAccount.Name := 'Test account';
+
+ exit(true);
+ end;
+
+ procedure DeleteAccount(AccountId: Guid): Boolean
+ var
+ TestEmailAccount: Record "Test Email Account";
+ begin
+ if TestEmailAccount.Get(AccountId) then
+ exit(TestEmailAccount.Delete());
+ exit(false);
+ end;
+
+ procedure GetLogoAsBase64(): Text
+ begin
+
+ end;
+
+ procedure GetDescription(): Text[250]
+ begin
+ exit('Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis ornare ante a est commodo interdum. Pellentesque eu diam maximus, faucibus neque ut, viverra leo. Praesent ullamcorper nibh ut pretium dapibus. Nullam eu dui libero. Etiam ac cursus metus.')
+ end;
+
+ procedure Reply(var EmailMessage: Codeunit "Email Message"; AccountId: Guid)
+ begin
+ if ConnectorMock.FailOnReply() then
+ Error('Failed to send email');
+ end;
+
+ procedure RetrieveEmails(AccountId: Guid; var EmailInbox: Record "Email Inbox"; var Filter: Record "Email Retrieval Filters" temporary)
+ begin
+ if ConnectorMock.FailOnRetrieveEmails() then
+ Error('Failed to retrieve emails');
+
+ ConnectorMock.CreateEmailInbox(AccountId, Enum::"Email Connector"::"Test Email Connector v3", EmailInbox);
+ EmailInbox.Mark(true);
+ ConnectorMock.CreateEmailInbox(AccountId, Enum::"Email Connector"::"Test Email Connector v3", EmailInbox);
+ EmailInbox.Mark(true);
+ end;
+
+ procedure MarkAsRead(AccountId: Guid; ConversationId: Text)
+ begin
+ if ConnectorMock.FailOnMarkAsRead() then
+ Error('Failed to mark email as read');
+ end;
+}
\ No newline at end of file
diff --git a/src/System Application/Test/Email/src/EmailTest.Codeunit.al b/src/System Application/Test/Email/src/EmailTest.Codeunit.al
index dc28d58a37..45ab5a8cfe 100644
--- a/src/System Application/Test/Email/src/EmailTest.Codeunit.al
+++ b/src/System Application/Test/Email/src/EmailTest.Codeunit.al
@@ -390,7 +390,6 @@ codeunit 134685 "Email Test"
Assert.ExpectedError(EmailMessageCannotBeEditedErr);
end;
-
[Test]
[HandlerFunctions('EmailEditorHandler,OnEmailEditorClose')]
procedure OpenInEditorModallyDiscardAOptionTest()
@@ -1403,6 +1402,7 @@ codeunit 134685 "Email Test"
var
EmailAccount: Record "Email Account";
EmailInbox: Record "Email Inbox";
+ TempFilters: Record "Email Retrieval Filters" temporary;
ConnectorMock: Codeunit "Connector Mock";
begin
// [Scenario] Retrieving emails with a V1 connector should fail
@@ -1412,12 +1412,14 @@ codeunit 134685 "Email Test"
// [When] Retrieving emails
// [Then] An error is thrown that the connector does not support this operation
- asserterror Email.RetrieveEmails(EmailAccount."Account Id", EmailAccount.Connector, EmailInbox);
+ asserterror Email.RetrieveEmails(EmailAccount."Account Id", EmailAccount.Connector, EmailInbox, TempFilters);
Assert.ExpectedError('The selected email connector does not support retrieving emails');
end;
+#if not CLEAN26
[Test]
- procedure RetrieveEmails()
+ [Obsolete('v2 connector is replaced by v3 connector.', '26.0')]
+ procedure RetrieveEmailsv2()
var
EmailAccount: Record "Email Account";
EmailInbox: Record "Email Inbox";
@@ -1438,7 +1440,9 @@ codeunit 134685 "Email Test"
InitialId := EmailInbox.Id;
// [When] Retrieving emails
+#pragma warning disable AL0432
Email.RetrieveEmails(EmailAccount."Account Id", EmailAccount.Connector, EmailInbox);
+#pragma warning restore AL0432
// [Then] The EmailInbox will be filled only with new emails and not existing ones
EmailInbox.FindSet();
@@ -1450,7 +1454,8 @@ codeunit 134685 "Email Test"
end;
[Test]
- procedure RetrieveEmailsFail()
+ [Obsolete('v2 connector is replaced by v3 connector.', '26.0')]
+ procedure RetrieveEmailsFailv2()
var
EmailAccount: Record "Email Account";
EmailInbox: Record "Email Inbox";
@@ -1472,7 +1477,73 @@ codeunit 134685 "Email Test"
ConnectorMock.FailOnRetrieveEmails(true);
// [When] Retrieving emails
+#pragma warning disable AL0432
asserterror Email.RetrieveEmails(EmailAccount."Account Id", EmailAccount.Connector, EmailInbox);
+#pragma warning restore AL0432
+
+ // [Then] The EmailInbox will be filled only with new emails and not existing ones
+ Assert.ExpectedError('Failed to retrieve emails');
+ end;
+#endif
+ [Test]
+ procedure RetrieveEmailsv3()
+ var
+ EmailAccount: Record "Email Account";
+ EmailInbox: Record "Email Inbox";
+ TempFilters: Record "Email Retrieval Filters" temporary;
+ ConnectorMock: Codeunit "Connector Mock";
+ InitialId: Integer;
+ begin
+ // [Scenario] Retrieving emails with a V3 connector will succeed and the EmailInbox will be filled only with new emails and not existing ones
+ PermissionsMock.Set('Email Edit');
+
+ // [Given] An email account with a V3 connector
+ // [Given] Existing emails in Email Inbox
+ ConnectorMock.Initialize();
+ ConnectorMock.AddAccount(EmailAccount, Enum::"Email Connector"::"Test Email Connector v3");
+
+ EmailInbox.DeleteAll();
+ ConnectorMock.CreateEmailInbox(EmailAccount."Account Id", EmailAccount.Connector, EmailInbox);
+ Assert.AreEqual(1, EmailInbox.Count(), 'Wrong number of emails in the inbox');
+ InitialId := EmailInbox.Id;
+
+ // [When] Retrieving emails
+ Email.RetrieveEmails(EmailAccount."Account Id", EmailAccount.Connector, EmailInbox, TempFilters);
+
+ // [Then] The EmailInbox will be filled only with new emails and not existing ones
+ EmailInbox.FindSet();
+ Assert.AreEqual(2, EmailInbox.Count(), 'Wrong number of emails in the inbox');
+
+ repeat
+ Assert.AreNotEqual(InitialId, EmailInbox.Id, 'The email should not be the same as the initial one');
+ until EmailInbox.Next() = 0;
+ end;
+
+ [Test]
+ procedure RetrieveEmailsFailv3()
+ var
+ EmailAccount: Record "Email Account";
+ EmailInbox: Record "Email Inbox";
+ TempFilters: Record "Email Retrieval Filters" temporary;
+ ConnectorMock: Codeunit "Connector Mock";
+ begin
+ // [Scenario] Retrieving emails with a V3 connector fails due to some error
+ PermissionsMock.Set('Email Edit');
+
+ // [Given] An email account with a V3 connector
+ // [Given] Existing emails in Email Inbox
+ ConnectorMock.Initialize();
+ ConnectorMock.AddAccount(EmailAccount, Enum::"Email Connector"::"Test Email Connector v3");
+
+ EmailInbox.DeleteAll();
+ ConnectorMock.CreateEmailInbox(EmailAccount."Account Id", EmailAccount.Connector, EmailInbox);
+ Assert.AreEqual(1, EmailInbox.Count(), 'Wrong number of emails in the inbox');
+
+ // [Given] An error occurs when retrieving emails
+ ConnectorMock.FailOnRetrieveEmails(true);
+
+ // [When] Retrieving emails
+ asserterror Email.RetrieveEmails(EmailAccount."Account Id", EmailAccount.Connector, EmailInbox, TempFilters);
// [Then] The EmailInbox will be filled only with new emails and not existing ones
Assert.ExpectedError('Failed to retrieve emails');
@@ -1495,8 +1566,9 @@ codeunit 134685 "Email Test"
asserterror Email.MarkAsRead(EmailAccount."Account Id", EmailAccount.Connector, Any.AlphabeticText(10));
Assert.ExpectedError('The selected email connector does not support marking emails as read');
end;
-
+#if not CLEAN26
[Test]
+ [Obsolete('v2 connector is replaced by v3 connector.', '26.0')]
procedure MarkEmailAsRead()
var
EmailAccount: Record "Email Account";
@@ -1514,6 +1586,7 @@ codeunit 134685 "Email Test"
end;
[Test]
+ [Obsolete('v2 connector is replaced by v3 connector.', '26.0')]
procedure MarkEmailAsReadFail()
var
EmailAccount: Record "Email Account";
@@ -1533,6 +1606,45 @@ codeunit 134685 "Email Test"
asserterror Email.MarkAsRead(EmailAccount."Account Id", EmailAccount.Connector, Any.AlphabeticText(10));
Assert.ExpectedError('Failed to mark email as read');
end;
+#endif
+
+ [Test]
+ procedure MarkEmailAsReadv3()
+ var
+ EmailAccount: Record "Email Account";
+ ConnectorMock: Codeunit "Connector Mock";
+ Any: Codeunit Any;
+ begin
+ // [Scenario] Marking email as read with a V3 connector should succeed with no errors
+ // [Given] An email account with a V3 connector
+ ConnectorMock.Initialize();
+ ConnectorMock.AddAccount(EmailAccount, Enum::"Email Connector"::"Test Email Connector v3");
+
+ // [When] Mark email as read
+ // [Then] No error occurs
+ Email.MarkAsRead(EmailAccount."Account Id", EmailAccount.Connector, Any.AlphabeticText(10));
+ end;
+
+ [Test]
+ procedure MarkEmailAsReadFailv3()
+ var
+ EmailAccount: Record "Email Account";
+ ConnectorMock: Codeunit "Connector Mock";
+ Any: Codeunit Any;
+ begin
+ // [Scenario] Marking email as read with a V3 connector fails due to some error
+ // [Given] An email account with a V3 connector
+ ConnectorMock.Initialize();
+ ConnectorMock.AddAccount(EmailAccount, Enum::"Email Connector"::"Test Email Connector v3");
+
+ // [Given] Force an error to occur when marking email as read
+ ConnectorMock.FailOnMarkAsRead(true);
+
+ // [When] Mark email as read
+ // [Then] An error occurs
+ asserterror Email.MarkAsRead(EmailAccount."Account Id", EmailAccount.Connector, Any.AlphabeticText(10));
+ Assert.ExpectedError('Failed to mark email as read');
+ end;
[Test]
procedure ReplyToEmailWithV1Connector()
@@ -1540,7 +1652,6 @@ codeunit 134685 "Email Test"
EmailAccount: Record "Email Account";
EmailMessage: Codeunit "Email Message";
ConnectorMock: Codeunit "Connector Mock";
- Any: Codeunit Any;
begin
// [Scenario] Replying to an email with a V1 connector should fail
// [Given] An email account with a V1 connector
@@ -1550,11 +1661,13 @@ codeunit 134685 "Email Test"
// [When] Reply to email
// [Then] An error is thrown that the connector does not support this operation
- asserterror Email.Reply(EmailMessage, Any.AlphabeticText(10), EmailAccount."Account Id", EmailAccount.Connector);
+ asserterror Email.Reply(EmailMessage, EmailAccount."Account Id", EmailAccount.Connector);
Assert.ExpectedError('The selected email connector does not support replying to emails');
end;
+#if not CLEAN26
[Test]
+ [Obsolete('v2 connector is replaced by v3 connector.', '26.0')]
procedure ReplyToEmail()
var
EmailAccount: Record "Email Account";
@@ -1570,10 +1683,11 @@ codeunit 134685 "Email Test"
// [When] Reply to email
// [Then] No error occurs and reply returns true
- Assert.IsTrue(Email.Reply(EmailMessage, Any.AlphabeticText(10), EmailAccount."Account Id", EmailAccount.Connector), 'Did not succeed in replying the email');
+ Assert.IsTrue(Email.Reply(EmailMessage, EmailAccount."Account Id", EmailAccount.Connector), 'Did not succeed in replying the email');
end;
[Test]
+ [Obsolete('v2 connector is replaced by v3 connector.', '26.0')]
procedure ReplyToEmailWithNoRecipients()
var
EmailAccount: Record "Email Account";
@@ -1589,7 +1703,44 @@ codeunit 134685 "Email Test"
// [When] Reply to email
// [Then] No error occurs and reply returns true
- asserterror Email.Reply(EmailMessage, Any.AlphabeticText(10), EmailAccount."Account Id", EmailAccount.Connector);
+ asserterror Email.Reply(EmailMessage, EmailAccount."Account Id", EmailAccount.Connector);
+ Assert.ExpectedError('You must specify a valid email account to send the message to');
+ end;
+#endif
+ [Test]
+ procedure ReplyToEmailv3()
+ var
+ EmailAccount: Record "Email Account";
+ EmailMessage: Codeunit "Email Message";
+ ConnectorMock: Codeunit "Connector Mock";
+ begin
+ // [Scenario] Replying to an email with a V2 connector should succeed with no errors
+ // [Given] An email account with a V2 connector
+ ConnectorMock.Initialize();
+ ConnectorMock.AddAccount(EmailAccount, Enum::"Email Connector"::"Test Email Connector v3");
+ CreateEmailReply(EmailMessage);
+
+ // [When] Reply to email
+ // [Then] No error occurs and reply returns true
+ Assert.IsTrue(Email.Reply(EmailMessage, EmailAccount."Account Id", EmailAccount.Connector), 'Did not succeed in replying the email');
+ end;
+
+ [Test]
+ procedure ReplyToEmailWithNoRecipientsv3()
+ var
+ EmailAccount: Record "Email Account";
+ EmailMessage: Codeunit "Email Message";
+ ConnectorMock: Codeunit "Connector Mock";
+ begin
+ // [Scenario] Replying to an email with a V2 connector should succeed with no errors
+ // [Given] An email account with a V2 connector
+ ConnectorMock.Initialize();
+ ConnectorMock.AddAccount(EmailAccount, Enum::"Email Connector"::"Test Email Connector v3");
+ CreateEmailReply(EmailMessage, '');
+
+ // [When] Reply to email
+ // [Then] No error occurs and reply returns true
+ asserterror Email.Reply(EmailMessage, EmailAccount."Account Id", EmailAccount.Connector);
Assert.ExpectedError('You must specify a valid email account to send the message to');
end;
@@ -1599,7 +1750,6 @@ codeunit 134685 "Email Test"
EmailAccount: Record "Email Account";
EmailMessage: Codeunit "Email Message";
ConnectorMock: Codeunit "Connector Mock";
- Any: Codeunit Any;
begin
// [Scenario] Replying to an email with a V1 connector should fail
// [Given] An email account with a V1 connector
@@ -1609,11 +1759,13 @@ codeunit 134685 "Email Test"
// [When] Reply to email
// [Then] An error is thrown that the connector does not support this operation
- asserterror Email.ReplyAll(EmailMessage, Any.AlphabeticText(10), EmailAccount."Account Id", EmailAccount.Connector);
+ asserterror Email.ReplyAll(EmailMessage, EmailAccount."Account Id", EmailAccount.Connector);
Assert.ExpectedError('The selected email connector does not support replying to emails');
end;
+#if not CLEAN26
[Test]
+ [Obsolete('v2 connector is replaced by v3 connector.', '26.0')]
procedure ReplyAllToEmail()
var
EmailAccount: Record "Email Account";
@@ -1629,10 +1781,11 @@ codeunit 134685 "Email Test"
// [When] Reply to email
// [Then] No error occurs and reply returns true
- Assert.IsTrue(Email.ReplyAll(EmailMessage, Any.AlphabeticText(10), EmailAccount."Account Id", EmailAccount.Connector), 'Did not succeed in replying the email');
+ Assert.IsTrue(Email.ReplyAll(EmailMessage, EmailAccount."Account Id", EmailAccount.Connector), 'Did not succeed in replying the email');
end;
[Test]
+ [Obsolete('v2 connector is replaced by v3 connector.', '26.0')]
procedure ReplyAllToEmailFail()
var
EmailAccount: Record "Email Account";
@@ -1651,7 +1804,47 @@ codeunit 134685 "Email Test"
// [When] Reply to email
// [Then] No error occurs and reply returns true
- Assert.IsFalse(Email.ReplyAll(EmailMessage, Any.AlphabeticText(10), EmailAccount."Account Id", EmailAccount.Connector), 'Did succeed in replying the email when it should fail');
+ Assert.IsFalse(Email.ReplyAll(EmailMessage, EmailAccount."Account Id", EmailAccount.Connector), 'Did succeed in replying the email when it should fail');
+ end;
+#endif
+
+ [Test]
+ procedure ReplyAllToEmailv3()
+ var
+ EmailAccount: Record "Email Account";
+ EmailMessage: Codeunit "Email Message";
+ ConnectorMock: Codeunit "Connector Mock";
+ begin
+ // [Scenario] Replying to an email with a V2 connector should succeed with no errors
+ // [Given] An email account with a V2 connector
+ ConnectorMock.Initialize();
+ ConnectorMock.AddAccount(EmailAccount, Enum::"Email Connector"::"Test Email Connector v3");
+ CreateEmailReplyAll(EmailMessage);
+
+ // [When] Reply to email
+ // [Then] No error occurs and reply returns true
+ Assert.IsTrue(Email.ReplyAll(EmailMessage, EmailAccount."Account Id", EmailAccount.Connector), 'Did not succeed in replying the email');
+ end;
+
+ [Test]
+ procedure ReplyAllToEmailFailv3()
+ var
+ EmailAccount: Record "Email Account";
+ EmailMessage: Codeunit "Email Message";
+ ConnectorMock: Codeunit "Connector Mock";
+ begin
+ // [Scenario] Replying to an email with a V2 connector fails due to some error
+ // [Given] An email account with a V2 connector
+ ConnectorMock.Initialize();
+ ConnectorMock.AddAccount(EmailAccount, Enum::"Email Connector"::"Test Email Connector v3");
+ CreateEmailReplyAll(EmailMessage);
+
+ // [Given] Force the connector to fail on reply
+ ConnectorMock.FailOnReply(true);
+
+ // [When] Reply to email
+ // [Then] No error occurs and reply returns true
+ Assert.IsFalse(Email.ReplyAll(EmailMessage, EmailAccount."Account Id", EmailAccount.Connector), 'Did succeed in replying the email when it should fail');
end;
[Test]
@@ -1661,7 +1854,6 @@ codeunit 134685 "Email Test"
EmailOutbox: Record "Email Outbox";
EmailMessage: Codeunit "Email Message";
ConnectorMock: Codeunit "Connector Mock";
- Any: Codeunit Any;
begin
// [Scenario] Replying to an email with a V1 connector should fail
// [Given] An email account with a V1 connector
@@ -1671,11 +1863,12 @@ codeunit 134685 "Email Test"
// [When] Reply to email
// [Then] An error is thrown that the connector does not support this operation
- asserterror Email.EnqueueReply(EmailMessage, Any.AlphabeticText(10), EmailAccount."Account Id", EmailAccount.Connector, EmailOutbox);
+ asserterror Email.EnqueueReply(EmailMessage, EmailAccount."Account Id", EmailAccount.Connector, EmailOutbox);
Assert.ExpectedError('The selected email connector does not support replying to emails');
end;
-
+#if not CLEAN26
[Test]
+ [Obsolete('v2 connector is replaced by v3 connector.', '26.0')]
procedure EnqueueReplyToEmail()
var
EmailAccount: Record "Email Account";
@@ -1693,12 +1886,13 @@ codeunit 134685 "Email Test"
// [When] Reply to email
// [Then] No error occurs and reply returns true
Assert.IsTrue(IsNullGuid(EmailOutbox."Message Id"), 'The email message id in the outbox should be empty');
- Email.EnqueueReply(EmailMessage, Any.AlphabeticText(10), EmailAccount."Account Id", EmailAccount.Connector, EmailOutbox);
+ Email.EnqueueReply(EmailMessage, EmailAccount."Account Id", EmailAccount.Connector, EmailOutbox);
Assert.AreEqual(EmailMessage.GetId(), EmailOutbox."Message Id", 'The email message id should be the same as the one in the outbox');
end;
[Test]
+ [Obsolete('v2 connector is replaced by v3 connector.', '26.0')]
procedure EnqueueReplyToEmailWithNoRecipients()
var
EmailAccount: Record "Email Account";
@@ -1715,7 +1909,50 @@ codeunit 134685 "Email Test"
// [When] Reply to email
// [Then] No error occurs and reply returns true
- asserterror Email.EnqueueReply(EmailMessage, Any.AlphabeticText(10), EmailAccount."Account Id", EmailAccount.Connector, EmailOutbox);
+ asserterror Email.EnqueueReply(EmailMessage, EmailAccount."Account Id", EmailAccount.Connector, EmailOutbox);
+ Assert.ExpectedError('You must specify a valid email account to send the message to');
+ end;
+#endif
+
+ [Test]
+ procedure EnqueueReplyToEmailv3()
+ var
+ EmailAccount: Record "Email Account";
+ EmailOutbox: Record "Email Outbox";
+ EmailMessage: Codeunit "Email Message";
+ ConnectorMock: Codeunit "Connector Mock";
+ begin
+ // [Scenario] Replying to an email with a V2 connector should succeed with no errors
+ // [Given] An email account with a V2 connector
+ ConnectorMock.Initialize();
+ ConnectorMock.AddAccount(EmailAccount, Enum::"Email Connector"::"Test Email Connector v3");
+ CreateEmailReply(EmailMessage);
+
+ // [When] Reply to email
+ // [Then] No error occurs and reply returns true
+ Assert.IsTrue(IsNullGuid(EmailOutbox."Message Id"), 'The email message id in the outbox should be empty');
+ Email.EnqueueReply(EmailMessage, EmailAccount."Account Id", EmailAccount.Connector, EmailOutbox);
+
+ Assert.AreEqual(EmailMessage.GetId(), EmailOutbox."Message Id", 'The email message id should be the same as the one in the outbox');
+ end;
+
+ [Test]
+ procedure EnqueueReplyToEmailWithNoRecipientsv3()
+ var
+ EmailAccount: Record "Email Account";
+ EmailOutbox: Record "Email Outbox";
+ EmailMessage: Codeunit "Email Message";
+ ConnectorMock: Codeunit "Connector Mock";
+ begin
+ // [Scenario] Replying to an email with a V2 connector should succeed with no errors
+ // [Given] An email account with a V2 connector
+ ConnectorMock.Initialize();
+ ConnectorMock.AddAccount(EmailAccount, Enum::"Email Connector"::"Test Email Connector v3");
+ CreateEmailReply(EmailMessage, '');
+
+ // [When] Reply to email
+ // [Then] No error occurs and reply returns true
+ asserterror Email.EnqueueReply(EmailMessage, EmailAccount."Account Id", EmailAccount.Connector, EmailOutbox);
Assert.ExpectedError('You must specify a valid email account to send the message to');
end;
@@ -1726,7 +1963,6 @@ codeunit 134685 "Email Test"
EmailOutbox: Record "Email Outbox";
EmailMessage: Codeunit "Email Message";
ConnectorMock: Codeunit "Connector Mock";
- Any: Codeunit Any;
begin
// [Scenario] Replying to an email with a V1 connector should fail
// [Given] An email account with a V1 connector
@@ -1736,18 +1972,19 @@ codeunit 134685 "Email Test"
// [When] Reply to email
// [Then] An error is thrown that the connector does not support this operation
- asserterror Email.EnqueueReplyAll(EmailMessage, Any.AlphabeticText(10), EmailAccount."Account Id", EmailAccount.Connector, EmailOutbox);
+ asserterror Email.EnqueueReplyAll(EmailMessage, EmailAccount."Account Id", EmailAccount.Connector, EmailOutbox);
Assert.ExpectedError('The selected email connector does not support replying to emails');
end;
+#if not CLEAN26
[Test]
+ [Obsolete('v2 connector is replaced by v3 connector.', '26.0')]
procedure EnqueueReplyAllToEmailFail()
var
EmailAccount: Record "Email Account";
EmailOutbox: Record "Email Outbox";
EmailMessage: Codeunit "Email Message";
ConnectorMock: Codeunit "Connector Mock";
- Any: Codeunit Any;
begin
// [Scenario] Replying to an email with a V2 connector fails due to some error
// [Given] An email account with a V2 connector
@@ -1760,7 +1997,30 @@ codeunit 134685 "Email Test"
// [When] Reply to email
// [Then] No error occurs and reply returns true
- Email.EnqueueReplyAll(EmailMessage, Any.AlphabeticText(10), EmailAccount."Account Id", EmailAccount.Connector, EmailOutbox);
+ Email.EnqueueReplyAll(EmailMessage, EmailAccount."Account Id", EmailAccount.Connector, EmailOutbox);
+ end;
+#endif
+
+ [Test]
+ procedure EnqueueReplyAllToEmailFailv3()
+ var
+ EmailAccount: Record "Email Account";
+ EmailOutbox: Record "Email Outbox";
+ EmailMessage: Codeunit "Email Message";
+ ConnectorMock: Codeunit "Connector Mock";
+ begin
+ // [Scenario] Replying to an email with a V2 connector fails due to some error
+ // [Given] An email account with a V2 connector
+ ConnectorMock.Initialize();
+ ConnectorMock.AddAccount(EmailAccount, Enum::"Email Connector"::"Test Email Connector v3");
+ CreateEmailReplyAll(EmailMessage);
+
+ // [Given] Force the connector to fail on reply
+ ConnectorMock.FailOnReply(true);
+
+ // [When] Reply to email
+ // [Then] No error occurs and reply returns true
+ Email.EnqueueReplyAll(EmailMessage, EmailAccount."Account Id", EmailAccount.Connector, EmailOutbox);
end;
local procedure CreateEmail(var EmailMessage: Codeunit "Email Message")