How to create an HTML Application to configure your IIS SMTP Username and Password settings

Like many IIS administrators, I usually install the local SMTP service on my IIS servers when I am setting up a new server from scratch. When I install the SMTP service, I configure it so that it only listens on the IP address of 127.0.0.1, so it can only send emails which originate on the server itself. What's more, I configure the SMTP service to relay all emails to a downstream SMTP service which can send emails out to the Internet. By configuring these options, I can write my ASP.NET, PHP, and Classic ASP applications so that they use the local SMTP service for all email-related functionality, which acts as a sort of message server for my applications. This system works great, and I have used this particular setup since the days of IIS 4.0. (Which was released in late 1997, as you may recall.)

That being said, in the interests of security, sometime ago I started using a downstream SMTP service which requires user credentials, (that way no one could use the downstream server anonymously). As an additional security step, I use an account which requires that the credentials are changed every 30 days or so. This is always a good security practice for a myriad of obvious reasons, but this meant that I needed to update the SMTP username/password settings in my IIS configuration settings every 30 days.

With that in mind, many years ago I wrote a simple VBScript application which I would use to update those credentials. At first I would simply enter the credentials directly into the script, then I would run it to update IIS, and then I would strip the credentials from the script. Needless to say, this was pretty low-tech - even considering that this was 17 or 18 years ago. I eventually updated the script so that it would use VBScript Input Boxes to prompt me for the credentials, so I no longer needed to store the credentials in the script itself. (Sometime after that I rewrote the script so that it would read the existing values from the IIS settings and pre-populate the input boxes.)

Jumping ahead a couple of years, I decided to rewrite the script as an HTML Application, which offered me considerably more options from a user interface perspective. That script has been serving me faithfully for some time now, so I thought that it would make a good blog subject.

Using the HTML Application

Using the application is pretty straight-forward; when you double click the HTA file, it will present you with the following user interface:

The script will read any existing credentials from your IIS settings and use those to pre-populate the interface. If no existing credentials are found, it will pre-populate the interface with the username of the currently-logged-on user.

Clicking Update will update your IIS settings, clicking Reset will reset the values back to the last saved version, and clicking Close will obviously close the application, but only after it has checked if you have any unsaved changes.

Creating the HTML Application

To create this HTML Application, save the following HTMLA code as "Reset SMTP Password.hta" to your computer, and then double-click its icon to run the application.

 <html>
<head>
<title>Reset SMTP Password</title>
<HTA:APPLICATION
  APPLICATIONNAME="Reset SMTP Password"
  ID="ResetSmtpPassword"
  VERSION="1.0"
  BORDER="dialog"
  BORDERSTYLE="static"
  INNERBORDER="no"
  CAPTION="yes"
  SYSMENU="no"
  MAXIMIZEBUTTON="no"
  MINIMIZEBUTTON="no"
  SCROLL="no"
  SCROLLFLAT="yes"
  SINGLEINSTANCE="yes"
  CONTEXTMENU="no"
  SELECTION="no"/>
<style>
<!--
body,input
{
 font-family:calibri,arial;
 font-size:9pt;
 color: #000;
 background-color: #fff;
}
table,td,th
{
 border:none;
}
-->
</style>
</head>

<script language="VBScript">
Option Explicit

' Define the global variables.
Dim objWMIService, objIIsSmtpServer
Dim strRouteUserName, strRoutePassword
Dim blnCancelBubble, blnPendingUpdates

' ----------------------------------------
' 
' Initialization method for the application.
' 
' ----------------------------------------

Sub Window_OnLoad

    ' Define the local variables.
    Dim objNetwork

    ' Set up the UI dimensions.
    Const intDialogWidth = 280
    Const intDialogHeight = 220
    ' Specify the window position and size.
    Self.resizeTo intDialogWidth,intDialogHeight
    Self.moveTo (Screen.AvailWidth - intDialogWidth) / 2, _
        (Screen.AvailHeight - intDialogHeight) / 2
        
    ' Enable events.
    blnCancelBubble = False
    blnPendingUpdates = False

    ' Set up some base objects for the local computer and default SMTP instance.
    ' Note that these settings can be customized for a different computer or SMTP instance.
    Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
    Set objIIsSmtpServer = GetObject("IIS://localhost/SmtpSvc/1")
    
    ' Retrieve the current username/password from the SMTP settings.
    strRouteUserName = objIIsSmtpServer.RouteUserName
    strRoutePassword = objIIsSmtpServer.RoutePassword
    
    ' Verify that a username was retrieved; otherwise, use the logged-on user.
    If Len(strRouteUserName)=0 Then
        Set objNetwork = CreateObject("WScript.Network")
        strRouteUserName = IIf(Len(objNetwork.UserDomain)>0, _
            objNetwork.UserDomain & "\","") & objNetwork.UserName
        Set objNetwork = Nothing
        blnPendingUpdates = True
    End If
    
    ' Store the username/password values in the UI.
    txtUsername.value = strRouteUserName
    txtPassword.value = strRoutePassword
    
End Sub

' ----------------------------------------
' 
' Implement the missing IIf() function.
' 
' ----------------------------------------

Function IIf(tx,ty,tz)
    If (tx) Then IIf = ty Else IIf = tz
End Function

' ----------------------------------------
' 
' Click handler for the Close button.
' 
' ----------------------------------------

Sub btnClose_OnClick()
    ' Test if we need to cancel bubbling of events.
    If blnCancelBubble = False Then
        ' Check if there are pending updates.
        If blnPendingUpdates = False Then
            ' If not, then close the application.
            Window.close
        ' Prompt the user to exit.
        ElseIf MsgBox("You have not saved your changes." & vbCrLf & _
                "Are you sure you wish to exit?", _
                vbYesNo+vbDefaultButton2+vbQuestion+vbSystemModal, _
                ResetSmtpPassword.applicationName)=vbYes Then
                ' Enable event bubbling.
                blnCancelBubble = True
                ' Close the application.
                Window.close
        End If
    End If
    ' Specify whether to bubble events.
       blnCancelBubble = IIf(blnCancelBubble=True,False,True)
End Sub

' ----------------------------------------
' 
' Change handler for text boxes.
' 
' ----------------------------------------

Sub Textbox_OnChange()
    ' Flag the application as having updates pending.
    blnPendingUpdates = True
End Sub

' ----------------------------------------
' 
' Focus handler for text boxes.
' 
' ----------------------------------------

Sub Textbox_OnFocus(objTextbox)
    ' Select the text in the textbox.
    objTextbox.Select
End Sub

' ----------------------------------------
' 
' Click handler for the Reset button.
' 
' ----------------------------------------

Sub btnReset_OnClick()
    ' Reset the username/password values in the UI.
    txtUsername.value = strRouteUserName
    txtPassword.value = strRoutePassword
    blnPendingUpdates = False
End Sub

' ----------------------------------------
' 
' Click handler for the Update button.
' 
' ----------------------------------------

Sub btnUpdate_OnClick()

    ' Catch bubbled events.
    If blnCancelBubble = True Then
        blnCancelBubble = False
        Exit Sub
    End If

    ' Verify valid data.
    If Len(txtUsername.value)=0 Or Len(txtPassword.value)=0 Then
        ' Inform the user that they made a mistake.
        MsgBox "An invalid username or password was entered.", _
            vbCritical + vbOKOnly, ResetSmtpPassword.applicationName
        ' Cancel event bubbling.
        blnCancelBubble = True
    Else
        ' Store the username/password values for the SMTP server.
        objIIsSmtpServer.RouteUserName = txtUsername.value
        objIIsSmtpServer.RoutePassword = txtPassword.value
        objIIsSmtpServer.SetInfo

        ' Save the username/password values.
        strRouteUserName = txtUsername.value
        strRoutePassword = txtPassword.value

        ' Flag the application as having no updates pending.
        blnPendingUpdates = False

        ' Cancel event bubbling.
        blnCancelBubble = True
    End If

End Sub
</script>

<body bgcolor="white" id="HtmlBody">
<div id="FormControls">
    <table>
        <tr><td>Please enter your SMTP credentials:</td></tr>
        <tr>
            <td align="left">
                <input type="text"
                style="width:250px;height:22px"
                name="txtUsername"
                id="txtUsername"
                onchange="Textbox_OnChange()"
                onfocus="Textbox_OnFocus(txtUsername)" />
            </td>
        </tr>
        <tr>
            <td align="left">
                <input type="password"
                style="width:250px;height:22px"
                name="txtPassword"
                id="txtPassword"
                onchange="Textbox_OnChange()"
                onfocus="Textbox_OnFocus(txtPassword)" />
            </td>
        </tr>
        <tr>
            <td align="right">
                <input type="button"
                style="width:125px;height:22px"
                name="btnUpdate"
                id="btnUpdate"
                value="Update"
                onclick="btnUpdate_OnClick()" />
            </td>
        </tr>
        <tr>
            <td align="right">
                <input type="button"
                style="width:125px;height:22px"
                name="btnReset"
                id="btnReset"
                value="Reset"
                onclick="btnReset_OnClick()" />
            </td>
        </tr>
        <tr>
            <td align="right">
                <input type="button"
                style="width:125px;height:22px"
                name="btnClose"
                id="btnClose"
                value="Close"
                onclick="btnClose_OnClick()" />
            </td>
        </tr>
    </table>
</div>
</body>
</html>

That's all that there is to it, although you might want to restart your SMTP service after you have made these changes.

Additional Notes

On a related topic, I get asked from time to time why I like to use HTML Applications (HTMLA) for some of my scripting examples, and the answer is quite simple: it is very easy to create powerful scripts in a very short amount of time which have sophisticated user interfaces and no compilation requirements.

I use Adersoft's HtaEdit as my IDE for HTMLA, which allows me to do normal development tasks like configuring project options, setting breakpoints, and stepping through my code.


Note: Click the image above to open it full-size in a separate window.

That being said, I have been experimenting with creating user interfaces in PowerShell, and it looks like it has some real promise for creating great UIs, too. But for now I only use PowerShell to create command line scripts, I use HTMLA to create cool UIs for administrative scripts, and I use C# to create "real" applications.