Skip to content

Commit

Permalink
Merge pull request #66 from mailjet/complex-variables
Browse files Browse the repository at this point in the history
Complex variables - fixes the case with
  • Loading branch information
sdiakovskyi-gd authored Dec 18, 2020
2 parents bfe9c70 + d9a6556 commit 9f9d451
Show file tree
Hide file tree
Showing 10 changed files with 267 additions and 8 deletions.
4 changes: 2 additions & 2 deletions Mailjet.Client/Mailjet.Client.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
<TargetFrameworks>net45;netstandard1.1</TargetFrameworks>
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>

<Version>2.0.0</Version>
<PackageVersion>2.0.0</PackageVersion>
<Version>2.0.1</Version>
<PackageVersion>2.0.1</PackageVersion>

<Authors>Mailjet, Dimitar Kostov</Authors>
<PackageLicenseUrl>https://github.com/mailjet/mailjet-apiv3-dotnet/blob/master/LICENSE</PackageLicenseUrl>
Expand Down
2 changes: 1 addition & 1 deletion Mailjet.Client/MailjetConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
public static class MailjetConstants
{
public const string DefaultBaseAdress = "https://api.mailjet.com";
public const string UserAgent = "mailjet-api-v3-net/2.0.0";
public const string UserAgent = "mailjet-api-v3-net/2.0.1";
public const string JsonMediaType = "application/json";
public const string ApiVersionPathV3 = "v3";
public const string ApiVersionPathV3_1 = "v3.1";
Expand Down
10 changes: 10 additions & 0 deletions Mailjet.Client/Resources/Template.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,21 @@ public static class Template
public const string APIKey = "APIKey";
public const string CategoriesSelectionMethod = "CategoriesSelectionMethod";
public const string PurposesSelectionMethod = "PurposesSelectionMethod";
public const string IsTextPartGenerationEnabled = "IsTextPartGenerationEnabled";
public const string User = "User";
public const string Limit = "Limit";
public const string Offset = "Offset";
public const string Sort = "Sort";
public const string CountOnly = "CountOnly";

public const long EditModeValue_DNDBuilder = 1;
public const long EditModeValue_HTMLBuilder = 2;
public const long EditModeValue_SavedSectionBuilder = 3;
public const long EditModeValue_MJMLBuilder = 4;

public const string OwnerTypeValue_Apikey = "apikey";
public const string OwnerTypeValue_User = "user";
public const string OwnerTypeValue_Global = "global";
}
}

Expand Down
5 changes: 3 additions & 2 deletions Mailjet.Client/Resources/TemplateDetailcontent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ public static class TemplateDetailcontent
public const string Htmlpart = "Html-part";
public const string MJMLContent = "MJMLContent";
public const string Headers = "Headers";
public const string From = "From";
public const string Subject = "Subject";
public const string ReplyTo = "Reply-to";
}
}


Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,6 @@ public class TransactionalEmail
public string URLTags { get; set; }

public Dictionary<string, string> Headers { get; set; }
public Dictionary<string, object> Variables { get; set; }
public IDictionary<string, object> Variables { get; set; }
}
}
18 changes: 16 additions & 2 deletions Mailjet.Client/TransactionalEmails/TransactionalEmailBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public class TransactionalEmailBuilder
private string _urlTags;

private Dictionary<string, string> _headers;
private Dictionary<string, object> _variables;
private IDictionary<string, object> _variables;

/// <summary>
/// The email subject line
Expand Down Expand Up @@ -393,6 +393,18 @@ public TransactionalEmailBuilder WithVariable(string variableName, object variab
return this;
}

/// <summary>
/// Adds dictionary with variables used to modify the content of your email.
/// Enter the information in the template text / HTML part by using the [[var:{var_name}]] format.
/// Equivalent of using X-MJ-Vars header through SMTP.
/// </summary>
public TransactionalEmailBuilder WithVariables(IDictionary<string, object> variables)
{
_variables = variables;

return this;
}

/// <summary>
/// Builds the mail message
/// </summary>
Expand Down Expand Up @@ -435,6 +447,7 @@ public TransactionalEmail Build()
/// with single preconfigured builder instance
/// performs the deep clone of the current builder instance
/// </summary>
/// <remarks>Clone creates a deep clone of the builder itself, but does not clone passed variables</remarks>
public TransactionalEmailBuilder Clone()
{
var result = (TransactionalEmailBuilder) MemberwiseClone();
Expand All @@ -459,7 +472,8 @@ public TransactionalEmailBuilder Clone()

private void Validate()
{
if (_from == null)
// template could have a default sender, so in case of using template we should allow sending w/o sender specified
if (_from == null && _templateId == null)
throw new MailjetClientConfigurationException("From field should be specified");

if (string.IsNullOrEmpty(_textPart) &&
Expand Down
180 changes: 180 additions & 0 deletions Mailjet.Tests/Integration/TemplateIntegrationTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Mailjet.Client;
using Mailjet.Client.Resources;
using Mailjet.Client.TransactionalEmails;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Newtonsoft.Json.Linq;

namespace Mailjet.Tests.Integration
{
[TestClass]
public class TemplateIntegrationTests
{
private MailjetClient _client;
private string _senderEmail;

[TestInitialize]
public async Task TestInitialize()
{
_client = new MailjetClient(Environment.GetEnvironmentVariable("MJ_APIKEY_PUBLIC"),
Environment.GetEnvironmentVariable("MJ_APIKEY_PRIVATE"));

_senderEmail = await GetValidSenderEmail(_client);
}

[TestMethod]
public async Task SendTransactionalEmailAsync_SendsEmail()
{
long templateId = await CreateTemplate();

Assert.IsTrue(templateId > 0);

await FillTemplateContent(templateId);

await SendEmailWithTemplate(templateId);

await DeleteTemplate(templateId);
}

private async Task DeleteTemplate(long templateId)
{
// arrange
MailjetRequest request = new MailjetRequest
{
Resource = Template.Resource,
ResourceId = ResourceId.Numeric(templateId)
};

// act
MailjetResponse response = await _client.DeleteAsync(request);

// assert
Assert.AreEqual(204, response.StatusCode);
}

private async Task FillTemplateContent(long templateId)
{
// arrange
var content = File.ReadAllText(Path.Combine("Resources", "MJMLTemplate.mjml"));

MailjetRequest request = new MailjetRequest
{
Resource = TemplateDetailcontent.Resource,
ResourceId = ResourceId.Numeric(templateId)
}
.Property(TemplateDetailcontent.MJMLContent, content)
.Property(TemplateDetailcontent.Headers, JObject.FromObject(new Dictionary<string, string>()
{
{"Subject", "Test transactional template subject " + DateTime.UtcNow},
{"SenderName", "Test transactional template"},
{"SenderEmail", _senderEmail},
{"From", _senderEmail},
}));

// act
MailjetResponse response = await _client.PostAsync(request);

// assert
Assert.IsTrue(response.IsSuccessStatusCode);
Assert.AreEqual(1, response.GetTotal());
Assert.AreEqual(content, response.GetData().Single().Value<string>("MJMLContent"));
}

private async Task<long> CreateTemplate()
{
// arrange
var templateName = "C# integration test template " + DateTime.UtcNow;

MailjetRequest request = new MailjetRequest
{
Resource = Template.Resource,
}
.Property(Template.Author, "Mailjet team")
.Property(Template.Copyright, "Mailjet")
.Property(Template.Description, "Used to send templated emails in C# SDK integration test")
.Property(Template.EditMode, Template.EditModeValue_MJMLBuilder)
.Property(Template.IsTextPartGenerationEnabled, true)
.Property(Template.Locale, "en_US")
.Property(Template.Name, templateName)
.Property(Template.OwnerType, Template.OwnerTypeValue_Apikey)
.Property(Template.Purposes, JArray.FromObject(new[]{ "transactional" }));

// act
MailjetResponse response = await _client.PostAsync(request);

// assert
Assert.IsTrue(response.IsSuccessStatusCode);

Assert.AreEqual(1, response.GetTotal());
Assert.AreEqual(templateName, response.GetData().Single().Value<string>("Name"));

long templateId = response.GetData().Single().Value<long>("ID");
return templateId;
}

public async Task SendEmailWithTemplate(long templateId)
{
// arrange
var testArrayWithValues = new []
{
new {title = "testTitle1"},
new {title = "testTitle2"},
};

var variables = new Dictionary<string, object>
{
{"testVariableName", "testVariableValue"},
{"items", testArrayWithValues}
};

var email = new TransactionalEmailBuilder()
.WithTo(new SendContact(_senderEmail))
.WithFrom(new SendContact(_senderEmail))
.WithSubject("Test subject " + DateTime.UtcNow)
.WithTemplateId(templateId)
.WithVariables(variables)
.WithTemplateLanguage(true)
.WithTemplateErrorDeliver(true)
.WithTemplateErrorReporting(new SendContact(_senderEmail))
.Build();

// act
var response = await _client.SendTransactionalEmailAsync(email);

// assert
Assert.AreEqual(1, response.Messages.Length);
var message = response.Messages[0];

Assert.AreEqual("success", message.Status);
Assert.AreEqual(_senderEmail, message.To.Single().Email);
}

public static async Task<string> GetValidSenderEmail(MailjetClient client)
{
MailjetRequest request = new MailjetRequest
{
Resource = Sender.Resource
};

MailjetResponse response = await client.GetAsync(request);

Assert.AreEqual(200, response.StatusCode);

foreach (var emailObject in response.GetData())
{
if (emailObject.Type != JTokenType.Object)
continue;

if (emailObject.Value<string>("Status") == "Active")
return emailObject.Value<string>("Email");
}

Assert.Fail("Cannot find Active sender address under given account");
throw new AssertFailedException();
}
}
}
10 changes: 10 additions & 0 deletions Mailjet.Tests/Mailjet.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@
<TargetFramework>netcoreapp1.1</TargetFramework>
</PropertyGroup>

<ItemGroup>
<None Remove="Resources\MJMLTemplate.mjml" />
</ItemGroup>

<ItemGroup>
<Content Include="Resources\MJMLTemplate.mjml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.0.0" />
<PackageReference Include="MSTest.TestAdapter" Version="1.1.11" />
Expand Down
41 changes: 41 additions & 0 deletions Mailjet.Tests/Resources/MJMLTemplate.mjml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<mjml owa="desktop" version="4.3.0">
<mj-head>
<mj-font href="https://fonts.googleapis.com/css?family=Montserrat" name="Montserrat"></mj-font>
<mj-font href="https://fonts.googleapis.com/css?family=Raleway" name="Raleway"></mj-font>
<mj-font href="https://fonts.googleapis.com/css?family=Open Sans" name="Open Sans"></mj-font>
<mj-preview></mj-preview>
</mj-head>
<mj-body background-color="#f8f8f8" color="#797e82" font-family="Open Sans, Helvetica, Arial, sans-serif">
<mj-section background-repeat="repeat" background-size="auto" padding-bottom="0px" padding-top="0px" padding="20px 0px 20px 0px" text-align="center" >
<mj-column>
<mj-text align="left" color="#797e82" font-family="Open Sans, Helvetica, Arial, sans-serif" font-size="11px" line-height="22px" padding-bottom="0px" padding-top="0px" padding="0px 0px 0px 25px">
<p style="text-align: center; margin: 10px 0;">
{{var:testVariableName:""}}
</p>
</mj-text>
</mj-column>
</mj-section>
<mj-section background-color="#ffffff" background-repeat="repeat" padding-bottom="0px" padding-left="0px" padding-right="0px" padding-top="0px" padding="20px 0" text-align="center" >
<mj-column>
<mj-divider border-color="#fcac24" border-style="solid" border-width="7px" padding-bottom="40px" padding-left="0px" padding-right="0px" padding-top="0px" padding="10px 25px" width="100%"></mj-divider>
</mj-column>
</mj-section>

<mj-raw>
{% for item in var:items %}
</mj-raw>

<mj-section background-color="#ffffff" background-repeat="repeat" background-size="auto" padding-bottom="70px" padding-top="30px" padding="20px 0px 20px 0px" text-align="center" >
<mj-column>
<mj-text align="left" color="#797e82" font-family="Open Sans, Helvetica, Arial, sans-serif" font-size="13px" line-height="22px" padding-bottom="0px" padding-left="50px" padding-right="50px" padding-top="0px" padding="0px 25px 0px 25px">
<h1 style="text-align:center; color: #000000; line-height:32px">Hey {{ item.title }}</h1>
</mj-text>
</mj-column>
</mj-section>

<mj-raw>
{% endfor %}
</mj-raw>

</mj-body>
</mjml>
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Check out all the resources and .NET code examples in the official [Mailjet Docu
- [Overview](#overview)
- [Table of contents](#table-of-contents)
- [Release notes](#release-notes)
- [v 2.0.1](#v-201)
- [v 2.0.0](#v-200)
- [Compatibility](#compatibility)
- [Dependencies .NETStandard 1.1](#dependencies-netstandard-11)
Expand Down Expand Up @@ -58,6 +59,8 @@ Check out all the resources and .NET code examples in the official [Mailjet Docu

## Release notes

### v 2.0.1
- TransactionalEmailBuidler now accepts variables of any type (previously only strings)
### v 2.0.0
- Added TransactionalEmailBuidler and TransactionalEmail strongly typed models - now you can send transactional emails more easily! Please, check [tests for more information](Mailjet.Tests/Integration/SendTransactionalEmailIntegrationTests.cs)
- Added Contacts delete API - now you can support [GDPR delete contacts](https://dev.mailjet.com/email/guides/contact-management/#gdpr-delete-contacts) easily
Expand Down

0 comments on commit 9f9d451

Please sign in to comment.