Skip to main content

Notifications and Emails

When Support Tickets are created, it would be good to have the ability to send an email to the person to whom the task has been assigned.

This feature will involve several steps, including downloading a NuGet package and verifying that there is an Assigned To attribute on the Ticket entity so that there will be a user to whom the email will be sent.

NOTE: This tutorial is built upon the foundation of the Support Ticket application.

1. Establish Email Settings

First you need to establish the configurations that will establish the email communication. Go to Config > App Features. Create a new page.

  • Set Name to: Email Notifications
  • Click Finish to establish the settings

Add the following Config Items (i.e., click Add Config Item):

  • Set Name to: SMTP Server
    Set Value Type to: Text
  • Set Name to: SMTP Port
    Set Type to: Number
    Set Default value to: 587
  • Set Name to: SMTP Login
    Set Type to: Text
  • Set Name to: SMTP Password
    Set Type to: Text
  • Set Name to: SMTP Email
    Set Type to: Text

2. Add NuGet Package

At the top of the Config subsection, click Resources

  • Click Add Resource
  • Select “Add NuGet Package Assembly Resource”
  • Search for MailKit. Click Add Package
  • Click OK

3. Establish Custom Code

Go to Code > Custom Code. Create a new page.

  • Set Name of file to: StmpMailer
  • Click Finish
  • Copy and paste the following:
using System.Collections.Generic;
using MailKit.Net.Smtp;
using MimeKit;
using MimeKit.Text;

namespace Util
{

internal class SmtpMailer
{
private readonly bool isEnabled;
private readonly string smtpServer;
private readonly int smtpPort;
private readonly string account;
private readonly string password;
private readonly string email;

public static readonly SmtpMailer Default = new SmtpMailer(
App.Features.EmailNotifications.IsEnabled,
App.Features.EmailNotifications.Config.SMTPServer,
App.Features.EmailNotifications.Config.SMTPPort,
App.Features.EmailNotifications.Config.SMTPLogin,
App.Features.EmailNotifications.Config.SMTPPassword,
App.Features.EmailNotifications.Config.SMTPEmail
);

public SmtpMailer(string smtpServer, int smtpPort, string account, string password) : this(true, smtpServer, smtpPort, account, password, account)
{

}

private SmtpMailer(bool isEnabled, string smtpServer, int smtpPort, string account, string password, string email)
{
this.isEnabled = isEnabled;
this.smtpServer = smtpServer;
this.smtpPort = smtpPort;
this.account = account;
this.password = password;
this.email = email;
}

public void SendEmail(string recipient, string subject, string content)
{
SendInternal(new [ ] { recipient }, subject, content, false);
}

public void SendHtmlEmail(string recipient, string subject, string htmlContent)
{
SendInternal(new [ ] { recipient }, subject, htmlContent, true);
}

public void SendMassEmail(IEnumerable<string> recipients, string subject, string content)
{
SendInternal(recipients, subject, content, false);
}

public void SendMassHtmlEmail(IEnumerable<string> recipients, string subject, string htmlContent)
{
SendInternal(recipients, subject, htmlContent, true);
}

public EmailBuilder NewEmail()
{
return new EmailBuilder(this);
}


private void SendInternal(IEnumerable<string> recipients, string subject, string content, bool isHtml, IEnumerable<EmailAttachment> attachments = null, string customSender = null)
{
if (!this.isEnabled)
{
return;
}

attachments = attachments ?? Enumerable.Empty<EmailAttachment>();


try
{
using(var client = new SmtpClient())
{
var message = new MimeMessage();
message.From.Add(MailboxAddress.Parse(customSender ?? this.email));
foreach(var recipient in recipients)
{
message.To.Add(MailboxAddress.Parse(recipient));
}

message.Subject = subject;

var bodyBuilder = new BodyBuilder();

if (isHtml)
bodyBuilder.HtmlBody = content;
else
bodyBuilder.TextBody = content;


foreach(var a in attachments)
{
bodyBuilder.Attachments.Add(a.FileName, a.ContentProvider(), ContentType.Parse("application/octet-stream"));
}

message.Body = bodyBuilder.ToMessageBody();

client.Connect(smtpServer, smtpPort);
client.Authenticate(new System.Net.NetworkCredential(account, password));
client.Send(message);
client.Disconnect(true);
}
}
catch (Exception e)
{
throw new Exception($"Could not send email [{smtpServer}:{smtpPort}, {account}]", e);
}
}

public class EmailBuilder
{
private string subject = null;
private string content = null;
private string sender = null;
private string replyTo = null;
private bool contentIsHtml = false;

private readonly List<string> recipients = new List<string>();
private readonly List<EmailAttachment> attachments = new List<EmailAttachment>();
private readonly SmtpMailer mailer;
public EmailBuilder(SmtpMailer mailer) { this.mailer = mailer; }

public EmailBuilder AddRecipient(string recipient)
{
this.recipients.Add(recipient);
return this;
}

public EmailBuilder AddRecipients(IEnumerable<string> recipients)
{
this.recipients.AddRange(recipients);
return this;
}

public EmailBuilder SetSender(string senderEmail)
{
this.sender = senderEmail;
return this;
}
public EmailBuilder SetReplyTo(string replyToEmail)
{
this.replyTo = replyToEmail;
return this;
}

public EmailBuilder SetSubject(string subject)
{
this.subject = subject;
return this;
}

public EmailBuilder SetPlainContent(string content)
{
this.content = content;
this.contentIsHtml = false;
return this;
}

public EmailBuilder SetHtmlContent(string content)
{
this.content = content;
this.contentIsHtml = true;
return this;
}

public EmailBuilder AddAttachments(IEnumerable<IDocument> documents)
{
foreach(var d in documents)
{
AddAttachment(d);
}
return this;
}

public EmailBuilder AddAttachments(IEnumerable<IDocumentRevision> documents)
{
foreach(var d in documents)
{
AddAttachment(d);
}
return this;
}

public EmailBuilder AddAttachment(IDocument document)
{
return AddAttachment(document.GetLatestRevision());
}

public EmailBuilder AddAttachment(IDocumentRevision documentRev)
{
if (documentRev == null)
{
return this;
}

this.attachments.Add(new EmailAttachment()
{
FileName = documentRev.FileName,
ContentProvider = () => documentRev.Content
});
return this;
}

public void Send()
{
mailer.SendInternal(recipients, subject, content, contentIsHtml, attachments, sender);
}
}


protected class EmailAttachment
{
public Func<byte[ ]> ContentProvider
{
get;
set;
}
public string FileName
{
get;
set;
}
}
}
}

4. Add 'Assigned To' Attribute

  • Go to Data > Entities and double-click Ticket
  • In Data Definition > Attributes, click Add New Attribute
  • Set Attribute Name to: Assigned To
  • Set Type to: User
  • Click Create Attributes
  • Save changes: Ctrl + S

5. Add 'Assigned To' Attribute to Ticket Detail Page

  • Go to UI > Entity Pages and double-click Ticket Detail
  • In the top Layout section, click Edit Layout
  • Add Assigned To to the layout.

6. Establish the Text for the Email

Go to Code > Templates. Create a new page.

  • Set Name of Template to: Text For Email
  • Set Template Code Language to: Html
  • Set Model Type to: Entity
  • Set Entity to: Ticket

Note: Assigned To is used in the template text below. It was created as an attribute on the Ticket entity as part of the Workflow advanced topic. If not, it needs to be added to establish the user to whom the email will be sent.

  • Copy and paste the following:
<html>

<head>
</head>

<body>
<table>
<tr>
<td>Ticket Assigned</td>
</tr>
<tr>
<td>Hi @Model.AssignedTo.Name ,</td>
</tr>
<tr>
<td>Ticket "@Model.Title" has been assigned to you.</td>
</tr>
<tr>
<td>Please resolve the issue as quickly as possible.</td>
</tr>
</table>
</body>

</html>
  • Click Finish

7. Establish Business Command to Send Email to Assigned Person

Go to Business > Commands. Create a new page.

  • Set Name to: Main Assigned Person
  • Set Type to: Entity Command
  • Set Entity to: Ticket
  • Copy and paste the following:
(ticket, db, ctx) =>
{
var content = App.Templates.TextForEmail.Render(ticket);
var subject = "Task Assigned";
var mail = ticket.AssignedTo.Email;

//this renders a template with task its called on
App.Templates.TextForEmail.Render(ticket);
//this sends email
Util.SmtpMailer.Default.SendHtmlEmail(mail, subject, content);
}

8. Update the Ticket Detail Page

Go to UI > Entity Pages and double-click Ticket Detail

  • At the top of the Layout section, click Add Action
  • Set Entity Command to: Main Assigned Person
  • In the UI section, set Button Label to: Send Email
  • Set Icon to: Envelope
  • Click OK

9. Release the App

10. Create a Production Instance

A Production instance should be created in order to send an email to an actual user.

  • Click + Create Instance
  • On the Create New Application Instance page, Set Instance Name to: Onboarding Production App
  • Set Hosting to: Jetveo Cloud
  • Set Application Type to: Production
  • Set Authentication to: Jetveo Login
  • Set Application to: Onboarding App
  • Set Application Version to the most recent release
  • Click Create

11. Configure Email Settings on the App Overview

  • Click Settings
  • Click the Features tab
  • Mark Email Notifications
  • Click Configure

Input the following information (i.e. click Change) according to your email server:
SMTP Server: TBD
SMTP Port: 587 (This should already be established.)
SMTP Login: TBD
SMTP Password: TBD
SMTP Email: TBD