Building an email application with Mailgun - Part 2

Updated December 8, 2019

Let's develop an email client to view and send messages.
We'll create a split-view layout, with email messages listed on the top half. Clicking an email message will display the full contents of the message on the bottom half. We'll add a left panel as well, where we'll place mail folders, and other webmail features.
Once finished, our email client will look like this:

In Part 1, we created an ASP.NET Core Web application in Visual Studio, and used it to set up the back-end for our email application. In Part 2, we'll use the same project to build the front-end portion.

When we created the project, we selected React and Redux as the project template. Visual Studio adds this template into a folder named ClientApp. This is where we are going to build the email client, so let's get familiar with the contents of this folder first.

1. Front-end development in Visual Studio

In our Visual Studio project, go to Solution Explorer, and double-click on the ClientApp folder. Inside ClientApp, there are two folders you want to keep in mind: public, and src.

In the public folder, you'll find an index.html file that serves as the root of your application. We'll use this file to include any external CSS or JavaScript resources.

The src folder contains all our scripts. Since React and Redux relies heavily on scripting, this is where we'll be doing most of our front-end development work.

Back in the ClientApp folder, open the package.json file to view the front-end dependencies included with our project. You should see dependency entries for the React and Redux libraries, along with their version number. We'll use React to build our webmail interface as class-based components. Redux will help us synchronize data across these components. Another important dependency to note is TypeScript. We'll use TypeScript to make our codebase more robust and less error-prone.

We'll want a sophisticated UI framework to create an engaging visual experience. For this purpose, we are going to install Material UI. Additionally, we'll need an extensible grid element to display a message list that allows for sorting and selection of messages. For this, we'll use the DevExtreme React Grid. Let's go ahead and install these dependencies to our project.

1.1 Installing dependencies

Go to Tools -> NuGet Package Manager, and select Package Manager Console. In the console, run the following commands to install the dependencies mentioned:

cd Cratemail/ClientApp replacing Cratemail with the name of your project.

Development Tip

You can also install dependencies from the command prompt instead. In Solution Explorer, right-click on the ClientApp folder and select Properties. From the properties window, copy the Full Path value. Now open a command prompt, type in cd, press the space key, then right-click to paste the full path, and press enter. The command should look like cd C:\path\to\project\Cratemail\ClientApp\. Finally, run the npm commands shown above, but make sure you have NodeJS installed in your system.

Also, let's improve text display in our mail client by using the Roboto font. We'll include this font as a CSS resource. Back in Solution Explorer, go to the ClientApp folder, double-click on the public folder, and open index.html. Copy the following line and paste it anywhere inside the head tag.

2. Designing the Inbox

With our dependencies ready, we can start developing our email application. Let's begin working on the inbox. First, we need to figure out how to access our mail data.

2.1 Application state

In Solution Explorer, go to ClientApp -> src. From this directory, double-click on the store folder. This folder is designated for working with data in Redux. Let's create a module here for our mail data. Right-click on store, then go to Add, select New Item, and add a new TypeScript file called Mailbox.ts.

In Redux, data is passed to your application via reducers. We'll create a reducer and plug in our mail data in Mailbox.ts. However, before we retrieve emails from our database, we'll create a simple data representation for now, so we can focus on designing our inbox first.

Go back to the store folder, and open index.ts. Add a reference to the reducer here to make it available for our application.

import*asMailboxStorefrom'./Mailbox';

exportinterfaceApplicationState {

mailbox: MailboxStore.Mailbox;

}

exportconstreducers = {

mailbox:MailboxStore.reducer,

}

Now we'll be able to integrate mail data in our React components.

2.2 Mailbox component

In Solution Explorer, go to ClientApp -> src, and double-click on the components folder. As the name suggests, the components folder is where you'll want to keep your React components. Let's create a component for our inbox. Right-click on the components folder, then go to Add, select New Item, and add a new TypeScript JSX file called Mailbox.tsx with the following content:

In this component, we are using the DevExtreme React Grid to display our mail data. We've also integrated sorting, so we can sort by recipient or date if needed. Clicking on a message row should display the message contents below the grid.

Let's go ahead and test our inbox. Back in Solution Explorer, go to ClientApp -> src, and open App.ts. Place the following code into this file:

importMailboxfrom'./components/Mailbox';

exportdefault () => (

<Mailbox/>

);

In Visual Studio, press F5 to start debugging. This should launch a new window with our inbox in view.

2.3 Integrating data

With our inbox design ready, let's have it pull in messages from our database. To do this, we'll create a GET handler for our API controller. In Solution Explorer, go to the Controller folder, and open MailController.cs. Add the following references:

usingSystem.Collections.Generic;

usingSystem.Data;

Now add the following GET handler to MailController.cs to retrieve all emails from our database:

With our GET handler in place, we can now pass mail data to our mail client through an API call. In Redux, API calls are placed in actions, which are then made available to your components via action creators. We'll add an action to request emails from our database.

Go to ClientApp -> src -> store, and open Mailbox.ts. Add the following content:

3. Building a message composer

So far, our mail client can only read messages. We need to be able to send messages as well. Let's add a Compose button that will allow us to send messages through a message composer. First, let's add a left panel to our layout where we can place our compose button.

3.1 Left panel

In Solution Explorer, go to ClientApp -> src, and open App.ts. Place the following code to add a left panel to our mail client.

In the code above, we are using the responsive drawer element from Material UI as our left panel. Our layout now has a place for buttons and mail folders. Press F5 to view the changes. It should look like this:

With the Compose button in place, we can now work on the message composer itself.

3.2 Composer component

In Solution Explorer, go to ClientApp -> src, and right-click on the components folder. Then, go to Add, select New Item, and add a new TypeScript JSX file called Composer.tsx with the following content:

In the code above, messages are sent as a PUT request to our API. To make our message composer work, we'll have to create a PUT handler in our API controller.

3.3 Sending email with Mailgun

In Solution Explorer, go to the Controllers folders and open MailController.cs. In our PUT handler, we'll send messages by passing them along to the Mailgun API. Add the following references to MailController.cs:

3.4 Finishing up

In Solution Explorer, go to ClientApp -> src, and open App.ts. Add a reference to the composer:

importComposerfrom'./components/Composer';

Add the following hook logic to the functional component:

const [view, setView] = React.useState(<Mailbox/>);

constchangeView = (viewName: string) => {

setTitle(viewName);

if (viewName == "Compose") {

setView(<Composer/>);

} else {

setView(<Mailbox/>);

}

}

Add a call to changeView on your compose button and your mail folders:

constdrawer = (

<div>

<divclassName={classes.drawerButtonContainer}>

<ButtononClick={() =>changeView("Compose")}

variant="contained"

color="primary"

size="large"

className={classes.drawerButton}

startIcon={<SendIcon/>}

>

Compose

</Button>

</div>

<Divider/>

<List>

{Folders.map((folder, index) => {

constIconComponent = folder.icon;

return (

<ListItembuttonkey={index}onClick={() =>changeView(folder.name)}>

<ListItemIcon><IconComponent/></ListItemIcon>

<ListItemTextprimary={folder.name}/>

</ListItem>

)

})}

</List>

</div>

);

Finally, place the view variable in the main content area:

<mainclassName={classes.content}>

<divclassName={classes.toolbar}/>

{view}

</main>

Press F5 in Visual Studio to test the message composer. You should now be able to send emails through your Mailgun account.

By now, you should have a mail client capable of viewing and sending emails with Mailgun. Let it serve as a starting point for building your own email application. Feel free to integrate additional features like an authentication layer, a spam filter, or custom mail folders.