Skip to main content
Ben Nadel at cf.Objective() 2017 (Washington, D.C.) with: Mike Sprague
Ben Nadel at cf.Objective() 2017 (Washington, D.C.) with: Mike Sprague@spraguey )

Using MailHog SMTP Server With ColdFusion And Docker

By on
Tags:

At work, we've been using an email testing tool called MailHog. I first learned about MailHog from my co-worker, Shawn Grigson, who added it to our Lucee CFML docker-compose.yaml file some years ago. MailHog provides both an SMTP server for receiving emails and a rather elegant user interface (UI) for reading and deleting said emails. Yesterday, I went to add MailHog into my personal blog's ColdFusion Docker setup; and, I was blown away at just how easy it was to get going.

The MailHog Docker image, mailhog/mailhog, exposes two ports: 1025 for receiving emails and 8025 for exposing the email management UI. In my docker-compose.yaml file, getting MailHog up and running is literally as simple as using this image and exposing the two ports on the host machine.

In the following docker-compose.yaml file, I am defining an Adobe ColdFusion 2021 server using the official Adobe Docker image. And, I'm defining the MailHog server. Note that I am installing the ColdFusion mail module, which is required in order to consume the smtpServerSettings property in our Application.cfc:

version: "2.4"

services:

  # Our ColdFusion server.
  cfml:
    image: "adobecoldfusion/coldfusion2021:2021.0.5"
    ports:
      - "8500:8500"
    environment:
      acceptEULA: "YES"
      password: "password"
      installModules: "mail:2021.0.05.330109"
    volumes:
     - "./wwwroot:/app"
    depends_on:
      - "mailhog"

  # Our SMTP server.
  mailhog:
    image: "mailhog/mailhog"
    ports:
      # - "1025:1025" # SMTP server that ColdFusion will send mail to.
      - "8025:8025" # Web UI that developers can access to check sent-mail.

While the MailHog Docker container exposes port 1025 for the SMTP server, I don't actually have to expose that port on the host machine. The cfml server and the mailhog server live on the same network and will be able to communicate seamlessly without that port being exposed to me, the developer. I only need 8025 exposed for the email management UI.

Running docker-compose up now brings up the MailHog server followed by the Adobe ColdFusion server. Our ColdFusion application leverages MailHog by way of the SMTP server settings in the Application.cfc file:

component
	output = false
	hint = "I define the application settings and event handlers."
	{

	// Define the application settings.
	this.name = "MailHogInColdFusion";
	this.applicationTimeout = createTimeSpan( 1, 0, 0, 0 );
	this.sessionManagement = false;
	this.setClientCookies = false;

	// For our SMTP server, we're going to use the MailHog container. The name of the
	// mail server corresponds to the name of the service in our Docker Compose file.
	this.smtpServerSettings = {
		server: "mailhog:1025"
	};

}

There is no username or password required for the MailHog SMPT server - it's just a local development tool. As such, all we have to do is provide the server name and port. Notice that the name of the server is the same as the service block defined in our docker-compose.yaml file.

To test this, I set up an old-school <frameset> that places my ColdFusion code next to the MailHog management UI:

<!doctype html>
<html>
<frameset rows="50%,50%" border="5" bordercolor="#000000">
	<!--- Our ColdFusion mail form. --->
	<frame src="./send.cfm" />
	<!--- Our running MailHog container. --->
	<frame src="http://127.0.0.1:8025" />
</frameset>
</html>

And then I created a very simple interface for sending mail via the CFMail tag:

<cfscript>

	// Setupt our default form values.
	param name="form.submitted" type="boolean" default=false;
	param name="form.to" type="string" default="";
	param name="form.subject" type="string" default="";
	param name="form.message" type="string" default="";

	if ( form.submitted ) {

		new Mail()
			.setFrom( "ben@example.com" )
			.setTo( form.to )
			.setSubject( form.subject )
			.setBody( form.message )
			.setSpoolenable( false ) // Send immediately.
			.send()
		;

		location( url = cgi.script_name, addToken = false );

	}

</cfscript>
<cfoutput>

	<!doctype html>
	<html lang="en">
	<head>
		<meta charset="utf-8" />
		<link rel="stylesheet" type="text/css" href="./send.css" />
	</head>
	<body>

		<h1>
			Using MailHog As SMTP Server With ColdFusion And Docker
		</h1>

		<form method="post">

			<label for="to">To:</label>
			<input id="to" type="text" name="to" />

			<label for="subject">Subject:</label>
			<input id="subject" type="text" name="subject" />

			<label for="message">Message:</label>
			<textarea id="message" name="message"></textarea>

			<button type="submit" name="submitted" value="true">
				Send Mail
			</button>

		</form>

	</body>
	</html>

</cfoutput>

And that's all there is to it! If we open up this ColdFusion application and start sending emails, you'll see that they instantly show up in the MailHog email management UI:

How cool is that?! And, with MailHog in place in my local ColdFusion development environment, I never have to worry about accidentally sending email to real users - everything gets caught and managed locally.

Want to use code from this post? Check out the license.

Reader Comments

15,329 Comments

@Michael,

10000% I used to just have my local dev environment hooked up to my real mail service (PostMark). And was just keeping fingers-crossed that I never messed it up. Now, worry-free development, always!

15,329 Comments

@Laurence,

Oh very cool, so nice to see that there are multiple options along the same lines. And loving the fact that services like this are making it so easy to plug-and-play with Docker!

Post A Comment — I'd Love To Hear From You!

Oops!
NEW: Some basic markdown formatting is now supported: bold, italic, blockquotes, lists, fenced code-blocks. Read more about markdown syntax »
Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.