Thursday, December 30, 2010

Integrating SalesForce.com with SumTotal LMS

Recently I obtained a developer’s license for SalesForce to play with and learn more about this environment. One of the things that I wanted to figure out in my playing was to integrate another web application as a tab into the SalesForce interface. I thought that it would be fun to figure out how to link our learning management system (LMS) up with SalesForce. We are using a LMS from SumTotal which is a pretty flexible application.

For those that are not familiar with what a LMS is, it is an application that provides an environment for keeping track of learning activities for users and many can also provide on-line learning content.
I will walk through much of the setup that I went through to get this to work though there are certain elements that I will not show for security reasons.

First off you would need to setup the remote application, in our case the LMS, to be able to receive a pass through authentication from SalesForce. For the SumTotal application I decided to use the MD5 pass through process. For simplicity of administration I decided to implement the authentication process a little differently than most. Most people that I have talked to will create the pass through authentication page and put it into the same web application as the LMS. There are two challenges with this.

I discovered the first of these challenges recently. This is how I had implemented the process initially though we just went through an upgrade of the application and this because a problem. I recommend NOT putting the pass through authentication pages in the same web application as the core LMS application.

The second issue is that the SumTotal web application is a precompiled J# application and putting uncompiled web pages into the same application can be tricky (not impossible, but tricky). For those who are not familiar with web development this can be a bit of a pain.

So with these two issues in mind, I took this approach. First of all we have a defined web instance (not the default instance) in IIS (Internet Information Services) dedicated to the LMS. There are a couple of virtual web folders, or web application, for the core application and its web services in the web site. I created two new virtual folders, or web applications, in the website. One for SSO pass through authentication and one for content that we would like to have exposed to the general public without going through the LMS (not important for this discussion). The SSO web application is not locked down since we want anyone to be able to access the pages to log in.

I created a script specifically to use with SalesForce (I do not like to mix authentication pages between different login processes). For simplicity I used J# to write the script though since I created my own web application for SSO I could have used any language. Below is a sample of the code that I used though you would need to modify a few things for it to work in your environment; css links and URLs. Also as a note I try to typically lock down the script so that it will only accept calls from certain web pages (referrers). Unfortunately when adding this call to SalesForce it makes the call without a referrer (similar to typing in the URL directly in the address line in your browser). This leaves a little bit of a security risk for your LMS which I have not figured out yet. The risk is that anyone who figures out the SSO URL could hack their way into the application (this is why I like to do referrer filtering). The MD5 authentication does not take a password for authentication. It assumes that authentication has already been performed in the source application and “trusts” the value being sent.

<%@ Page Language="VJ#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
public String user;
private void getUserName(Object obj, System.EventArgs e)
{
// Load NameValueCollection object.
NameValueCollection coll = get_Request().get_QueryString();
String test = coll.get_Item("username");
String Name = coll.get_Item("username");
String username = Name;
user = username;
rtUserID.set_Value(username);
String validreferrer1 = "";
int validreferrer = -1;
String errorurl = "/sumtotal/app/SilentLogon_Error.aspx?UserName=" + user + "&SilentLogonError=-5";
try
{
Uri referrerUrl = get_Request().get_UrlReferrer();
String httpreferrer = referrerUrl.get_AbsoluteUri().ToString();
get_Response().Write(httpreferrer);
if(httpreferrer.indexOf(validreferrer1) > -1)
{
validreferrer=1;
}
if(validreferrer < 0)
{
get_Response().Redirect(errorurl);
}
}
catch (Throwable t)
{
//get_Response().Redirect(errorurl);
}
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
<title> New Document </title>
<meta name="Generator" content="Microsoft FrontPage 4.0" />
<script type="text/javascript" language="JavaScript" src="md5.js"></script>
<meta name="Author" content="" />
<meta name="Keywords" content="" />
<meta name="Description" content="" />
<link rel='stylesheet' type='text/css' href='/SumTotal/client/media/css/default_800/SYS_base.css' />
<link rel='stylesheet' type='text/css' href='/SumTotal/client/media/css/default_800/Custom_SYS_base.css' />
</head>
<body onload='content_onload()'>
<script type="text/javascript" language="JavaScript">
//<!--
function getAuthCode()
{
var strEmp = String(document.getElementById('rtUserID').value);
var strtime_stampStamp = String(document.getElementById('time_stamp').value);
var strKey = String(document.getElementById('MD5Key').value);
document.getElementById('auth_token').value=hex_md5(strEmp+strtime_stampStamp+strKey);
}
function content_onload()
{
var dt = new Date();
document.getElementById('time_stamp').value= dt.getUTCFullYear() + ":" + (dt.getUTCMonth()+1) + ":" + dt.getUTCDate() + ":" + dt.getUTCHours () + ":" + dt.getUTCMinutes() + ":" + dt.getUTCSeconds();
getAuthCode();
document.getElementById('frmLogon').submit();
}
//-->
</script>
<form onload="getUserName" id="frmLogon" runat="server" method="post" action="/SumTotal/app/SYS_login.aspx">
<input type="hidden" runat="server" id="rtUserID" name='rtUserID' />
<input type="hidden" runat="server" id="time_stamp" name="time_stamp" value="2003:07:10:09:30:05" />
<input type="hidden" runat="server" id="MD5Key" name="MD5Key" value="12345" />&nbsp;
<input type="hidden" runat="server" id="auth_token" name="auth_token" />
<table width='100%' cellpadding="0" cellspacing="0" border="0">
<tr>
<td id='mainLeftTD' class='clsPageHeaderLeft' align=left valign=center nowrap>
<table>
<tr>
<td align=left valign=center nowrap>&nbsp;
<image border=0 src='/SumTotal/client/media/images/default_dlx_800/page_header_logo.gif' alt=''>
</td>
</tr>
</table>
</td>
<td id='mainRightTD' class='clsPageHeaderRight' style='background-image: url(/SumTotal/client/media/images/default_dlx_800/page_header_background.gif)' cellpadding=0 cellspacing=0 border=0>
</td>
</tr>
</table>
<br />
<br />
<br />
<br />
<table border="0" width="100%">
<tr>
<td>&nbsp;</td>
<td></td>
</tr>
<tr>
<td>&nbsp;</td>
<td></td>
</tr>
<tr>
<td>&nbsp;</td>
<td></td>
</tr>
<tr>
<td>&nbsp;</td>
<td></td>
</tr>
<tr>
<td colspan="2" align="center">
<font size="4"><b>You are now being logged into the SumTotal LMS as <%=user%>.... <i>Please wait</i></b></font>
</td>
</tr>
<tr>
<td align="center">
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<font size="1"><i>If you are not redirected in 5 seconds please press the button below.</i></font>
</td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="submit" value="Log On" name="btnToLogonPage" onclick='getAuthCode()' />
</td>
</tr>
</table>
</form>
</body>
</html>
Now that you have the SSO script in place you will need to expose the LMS to the outside world. If you are using the hosted version of the application it should already be exposed though I am not sure how to setup custom authentication paths using that model. Our LMS is an on-site installation. There are many methods for exposing a website to the outside world which is beyond the topic of this article.

For this exercise I created a test domain and test account to play with so that I do not impact any live accounts.

That is all that is needed on the LMS side of things though I recommend testing the URL to the new pass through page to make sure that it works prior to going to the SalesForce setup.

If you have not already created a developer account in SalesForce I recommend it. You can go to http://developer.force.com/ to create the account. When you create an account you will get a blank SalesForce site to play with (in the screenshots my site will have miscellaneous items in it due to may playing around in the site prior to this article).

First off you will need to decide what data element in the user profile to use that will match the user ID in the LMS. In the dropdown next to your login name you will see an option for “setup”. Select that option and the setup for the site will come up. Close to the bottom of the left hand side under “Administration Setup” there is an option called “Manage Users”. Open that up and select “Users”. Click on the user in the right hand side that you want to test with. There are many options that can be used. I selected to use the “Employee Number” option. The value in that field will match the user id that I setup in the LMS, in this case it is “testuser”.

clip_image002

Now that you have a user value that matches something in the LMS it is time to add the link in SalesForce. While still in “setup” on the left hand side go to the “App Setup” section, open the “create” menu and select “Tabs”. Mine looks like the below image though yours may be blank depending upon if you have added anything as of yet.

clip_image004

Click on the “New” button under the “Web Tabs”. A wizard will come up to help you through the tab creation process.

The first page in the wizard is below. You can use either format. I am going to use the “full page width” option because I think it looks better. Select “Next” after you have made your selection.

clip_image006

On the next wizard screen there are a lot of options that control how the linked object is displayed within the SalesForce environment. First give your new tab a Label and a Name. Select a tab style (color and icon) that you want to be associated to it (I selected the “Presenter” style). By default the “height” of the tab is set to 600. This controls whether the scroll bar will be displayed depending upon how big the page is. We try to have things in 800 pixel size so I entered 800. I have not tested the LMS with a mobile device so I am not sure if it is “mobile ready”. I do not have any splash pages defined so I do not need to select anything here. Lastly add a description. This is best practice to always add descriptions to your objects. Click “Next” when you are done.

clip_image008

The next wizard screen is where you add the URL link and pass the values that the application will need. The two dropdowns are there just for ease of use in finding the right syntax to use to pass the right value from SalesForce to the application. I put my URL in the URL box (you will note that my actual URL in this screen is not visible. You would need to have your actual URL to put in this space. One note is that you are only able to pass values via the query string. After you are done with your URL string press the “Next” button.

clip_image010

The next two screens control who can use the new tab and what applications it is available under. Once you click “Save” on the last tab you will be brought back to the main page that shows all the tabs in the application. You should also see the new tab at the top of the SalesForce interface.

clip_image012

Now if I go and click on the LMS tab in the SalesForce interface I will now see the pass through page for a moment and then it will forward on to the home page for the user.

clip_image014

Monday, December 27, 2010

Interesting Flash issue

Recently I came across an interesting issue with an application that uses flash.  My son received a LeapFrag MyPal as a present for Christmas.  There is an application that you can download from their site to personalize the toy to your child.  I downloaded the application and it installed without error.  It was a 32 bit application and installed in the right environment.  When the application started I received a prompt that the correct version of flash was not installed and it prompted me to download and install Flash which ends up erroring out.  I verified that the version of Flash that the application wants is the same version that is on my machine (10.1.102.64).  Just to make sure that I was not missing anything I installed Flash from Adobe's website and it installed fine (or more appropriately verified that I have the most recent version installed).

At this point I was very frustrated with the install until I started to think about the environment that I was working in.  I am running a 64 bit version of Windows 7 and Flash is a 32 bit application and as such Flash is installed in the path C:\Windows\SysWOW64\Macromed\Flash\.  I made a guess that the application is probably doing a version check of the Flash binary using a hard coded path to the default installation path.  In most situations this is C:\Windows\System32\Macromed\Flash\.  In a Windows 64 bix OS all the 64 binaries are stored in the C:\Windows\System32 folder (even though this sounds a bit odd) so flash would not be installed at this location.

So even though I know that the Flash binaries would not work in the C:\Windows\System32 folder in order to get the application to get past this binary version check I copied the Macromed folder and its contents to the C:\Windows\System32 folder and now the application works and Flash still works (since it is really executing via the C:\Windows\SysWOW64\ path).

Not a pretty workaround and is, in my opinion,  a flaw in the application it works without impacting any other applications.

Tuesday, August 10, 2010

Oracle: Check to see if a value is numeric

One of the functions that MS SQL has that Oracle does not have by default (which can be frustrating at times) is a function that checks to see if a value is numeric. After playing around a bit and digging through oracle in line function documentation I finally found something that would pass for this functionality.

I wanted something that would provide a result of 0 (is not numeric) or 1 (is numeric). Below is a SQL statement that I used during th e"playing" around process.

SELECT
    CASE WHEN nvl(length(translate(trim('111d'), ',.+-0123456789', ' ')),0) > 0 THEN 0 ELSE 1 END NonNumeric,
    CASE WHEN nvl(length(translate(trim('1111'), ',.+-0123456789', ' ')),0) > 0 THEN 0 ELSE 1 END Numeric
FROM DUAL
The idea behind this code is that first we take a string value (or field) and use the translate function to remove all of the numeric values and characters that are used with numeric values with nothing. Around that value I used the length function to return the length of "translated" value. I then evaluate the length. If it is larger than zero then I return a value of 1, becuase any value with a length greater than zero has a non-numeric character in it. Otherwise it returns a value of 1 (which means that the value is a numeric value).

I attempted to put together syntax to create a function called ISNUMERIC and pasted it below. I do not have an Oracle database on this server or have access to an Oracle in this environment to be able to run this code to make sure that it executes properly. I believe it will work though it has not been tested.

CREATE OR REPLACE FUNCTION ISNUMERIC (VALUE IN VARCHAR2)
    RETURN NUMBER
AS
BEGIN
  IF nvl(length(translate(trim(VALUE), ',.+-0123456789', ' ')),0) > 0
  THEN
    RETURN 0
  ELSE
    RETURN 1
  END IF
END ISNUMERIC;

Monday, August 9, 2010

Utility to check to see if a database is alive

A while back I had a need to come up with a quick and easy solution to be able to check whether a database was available via a command line utility.  The client had a software package that had the ability to run a command line application and read the results and record that to monitor the up time for database.

I decided to go with a simple VB solution using Visual Studio 2005.  I am sure there are better ways to accomplish the same thing though time was of the essence and I needed a workable solution and only had a day to do it.

I started off creating a new Visual Basic console project in Visual Studio.  I deleted the default module that was part of the project when it was created and created a new module named MainModule.  I added a new class to the module to manage the database connections.

I started with the connection class.  I needed to be able to handle multiple types of database connections.  Best practice is to have a class for each type of database connection all of which having the same functions to more ligically handle and manage the different code needed for the different connections.  I did not have time to do best practice.  Instead I put in a switch statement to manage the different database types.

First off I created class level variables to manage connection variables.
Private _oracleConnString As String

Private _sqlConnString As String
Private _odbcConnString As String

Private _dataType As String
Private _dataSource As String
Private _userId As String
Private _password As String
Private cnOracle As OracleClient.OracleConnection
Private cnSql As SqlClient.SqlConnection
Private cnOdbc As Odbc.OdbcConnection

Private writer As StreamWriter
Private logFile As String
After the variables I added a "New" sub procedure which receives values that are assigned to the class level variables.

Public Sub New(ByVal DataType As String, ByVal DataSource As String, ByVal UserID As String, ByVal Password As String)

_dataType = DataType
_dataSource = DataSource
_userId = UserID
_password = Password

_oracleConnString = "Data Source=[DATASOURCE];Persist Security Info=True;User ID=[USERID];Password=[PASSWORD];Unicode=True"
_sqlConnString = "Data Source=[DATASOURCE];Persist Security Info=True;User ID=[USERID];Password=[PASSWORD]"
_odbcConnString = "Dsn=[DATASOURCE];uid=[USERID];pwd=[PASSWORD]"

logFile = "dbcheck.log"
writer = New StreamWriter(logFile, True)
End Sub
The last part of this class is a function for the module code to call to open the database connection and return a result.  The function starts off with a variable to store a boolean value on whether the connection was successful or not.  The value of this variable is the return result for the function.  After that I created a switch statement based upon the database connection type (MS SQL, Oracle or ODBC).  Each connection attempt is surrounded by a try/catch statement.  If there are any errors the process writes the error to an error log.
 
Dim success As Boolean = False


Select Case _dataType

Case "Oracle"
_oracleConnString = _oracleConnString.Replace("[DATASOURCE]", _dataSource)
_oracleConnString = _oracleConnString.Replace("[USERID]", _userId)
_oracleConnString = _oracleConnString.Replace("[PASSWORD]", _password)
cnOracle = New OracleClient.OracleConnection(_oracleConnString)

Try
cnOracle.Open()
cnOracle.Close()
Return 1
Catch ex As Exception
Console.Write(ex.Message)
writer.WriteLine(Now.ToString())
writer.WriteLine(ex.Message)
Return 0
End Try

Case "SQL"
_sqlConnString = _sqlConnString.Replace("[DATASOURCE]", _dataSource)
_sqlConnString = _sqlConnString.Replace("[USERID]", _userId)
_sqlConnString = _sqlConnString.Replace("[PASSWORD]", _password)
cnSql = New SqlClient.SqlConnection(_sqlConnString)

Try
cnSql.Open()
cnSql.Close()
Return 1
Catch ex As Exception
Console.Write(ex.Message)
writer.WriteLine(Now.ToString())
writer.WriteLine(ex.Message)
Return 0
End Try

Case Else
_odbcConnString = _odbcConnString.Replace("[DATASOURCE]", _dataSource)
_odbcConnString = _odbcConnString.Replace("[USERID]", _userId)
_odbcConnString = _odbcConnString.Replace("[PASSWORD]", _password)
cnOdbc = New Odbc.OdbcConnection(_odbcConnString)

Try
cnOdbc.Open()
cnOdbc.Close()
Return 1
Catch ex As Exception
Console.Write(ex.Message)
writer.WriteLine(Now.ToString())
writer.WriteLine(ex.Message)
Return 0
End Try
End Select
Now that the connection class is complete it was time to put together the code for the main sub procedure in the main module that will capture the command line arguments and perform the connection test using the provided arguments.
 
I started off with the declaration of variables
Dim _dataType As String

Dim _dataSource As String
Dim _userId As String
Dim _password As String
Dim I As Integer = 0
Now that the variables are declared I added a process to cycle through the provided command line arguments and assign the values to the proper variables.

For Each arg As String In args

If arg.ToUpper = "/DATATYPE" Then
_dataType = args(I + 1)
End If

If arg.ToUpper = "/DATASOURCE" Then
_dataSource = args(I + 1)
End If

If arg.ToUpper = "/USERID" Then
_userId = args(I + 1)
End If

If arg.ToUpper = "/PASSWORD" Then
_password = args(I + 1)
End If

i = i + 1
Next
After the arguments are processed it is time to add the code that calls the connection class and tests to see if the connection is successful.

Dim success As Integer = 0


Try
Dim cn As Connection = New Connection(_dataType, _dataSource, _userId, _password)
success = cn.Open()
Catch ex As Exception
Console.Write(ex.Message)
End Try
If success = 1 Then
Console.Write("SUCCESS")
Else
Console.Write("FAILURE")
End If
A sample command line to execute this utility is:
dbcheck.exe /DATATYPE SQL /DATASOURCE SERVERNAME /USERID USERNAME /PASSWORD PASSWORD
To download a copy of the code click this link.

Sunday, August 8, 2010

How to create a utility to send an email via the command line

A while ago I came across a need to create a utility that can send email from the command line.  The reason for this is that the client I was working with had an application that did not have email support but it did have the ability to make a call from the command line.  The client needed to have a process that could pick up a file that is generated from the application and send it to an email address.

There are quite a few ways to accomplish this and there are already some utilities that I have seen that can do this though my need was to have a solution in a very short period in time.  There was no need for any bells and whistles.  They only needed the base functionality to being able to send the file via email and they needed the solution as soon as possible.

I decided to build the utility using Visual Studio 2005 with Visual Basic (though C# is currently my preferred language).

I began by creating a console application called "sendmail".  I deleted the default module that was created when the project was created.  I added a new module named "SMTPMail".  In that module I have two classes, SMTPMail and SendNewMail.

The SMTPMail class is where I will setup the properties and functions needed to send the email.  The SendNewMail class is used as a wrapper to collect the informaion from the command line and pass it to the SMTPMail class.

In the SMTPMail class I first added variables needed to store the infomation to send the email
Private _from As String
Private _to As String
Private _toName As String
Private _cc As String
Private _bcc As String
Private _attachment As Attachment
Private _subject As String
Private _body As String
Private _smtpPort As Integer = 25
Private _smtpServer As String
Next I defined the properties needed to populate the variables

Public Property SendFrom() As String

Get
Return _from
End Get
Set(ByVal value As String)
_from = value
End Set
End Property

Public Property SendTo() As String
Get
Return _to
End Get
Set(ByVal value As String)
_to = value
End Set
End Property

Public Property SendToName() As String
Get
Return _toName
End Get
Set(ByVal value As String)
_toName = value
End Set
End Property

Public Property SendCC() As String
Get
Return _cc
End Get
Set(ByVal value As String)
_cc = value
End Set
End Property

Public Property SendBCC() As String
Get
Return _bcc
End Get
Set(ByVal value As String)
_bcc = value
End Set
End Property

Public Property SendSubject() As String
Get
Return _subject
End Get
Set(ByVal value As String)
_subject = value
End Set
End Property

Public Property SendBody() As String
Get
Return _body
End Get
Set(ByVal value As String)
_body = value
End Set
End Property

Public Property SMTPPort() As Integer
Get
Return _smtpPort
End Get
Set(ByVal value As Integer)
_smtpPort = value
End Set
End Property

Public Property SMTPServer() As String
Get
Return _smtpServer
End Get
Set(ByVal value As String)
_smtpServer = value
End Set
End Property
The next step was to add a function to prepare the email message

Public Function PrepareMessage() As MailMessage

Dim toAddr As New MailAddress(_to, _toName)
Dim msg As New MailMessage(_from, _to, _subject, _body)

If Not _toName = String.Empty Then
msg.To.Clear()
msg.To.Add(toAddr)
End If

If Not _attachment Is Nothing Then
msg.Attachments.Add(_attachment)
End If

If _cc <> "" Then
msg.CC.Add(_cc)
End If

If _bcc <> "" Then
msg.Bcc.Add(_bcc)
End If

Return msg
End Function
The last elements that would need to be added to this class are the sub procedures needed to add the attachment to the message and the procedure to send the message.
 
Public Sub AddAttachment(ByVal FilePath As String)

_attachment = New Attachment(FilePath)
End Sub

Public Sub Send()
Dim mailClient As New SmtpClient(_smtpServer, _smtpPort)
mailClient.Send(PrepareMessage)
End Sub
I did not add any comments (which is bad form) and there is not much explanation on each of the lines of code though it is very self explanitory if you are familiar with VB. 
 
Next I needed to add the code to the SendNewMail class to collect the information from the command line and send it to the SendMail class.
 
Within this class there is only one sub procedure, "Main".  This is the procudure that will be called by the console when the executable is run.  I began editing this procedure similar to the other class by creating the variables I needed to store the information passed from the command line.
 
Dim _sendMail As New SMTPMail
Dim _trace As Boolean = False
Dim trace As String
Dim logFile As String = "sendmail.log"
Dim writer As StreamWriter = New StreamWriter(logFile, True)
Dim i As Integer = 0

NOTE:  The variable "_trace" is a boolean variable used to see if the user wants to create a log file to log all the transactions that pass through the executable.
 
Next I setup a for/next loop to cycle through each of the parameters that are passed from the command line and sets the variables with the passed values where appropriate.  A sample of the command line that I wanted to use would look like this:

c:\projects\sendmail\sendmail.exe /SMTPServer "servername" /To "bob@test.com" /From "sam@test.com" /Subject "test email" /Attachment "c:\projects\sendmail\test.pdf"
The for/next loop needed to be able to handle a command line in this format.  If any of the desired parameters are found in the command line arguments then the process will take the argument directly after it and assign it to the appropriate variable

For Each str As String In args

If str = "/SMTPServer" Then
_sendMail.SMTPServer = args(i + 1).Replace("", """")
End If

If str = "/SMTPport" Then
_sendMail.SMTPPort = args(i + 1).Replace("", """")
End If

If str = "/To" Then
_sendMail.SendTo = args(i + 1).Replace("", """")
End If

If str = "/ToName" Then
_sendMail.SendToName = args(i + 1).Replace("", """")
End If

If str = "/From" Then
_sendMail.SendFrom = args(i + 1).Replace("", """")
End If

If str = "/Subject" Then
_sendMail.SendSubject = args(i + 1).Replace("", """")
End If

If str = "/Body" Then
_sendMail.SendBody = args(i + 1).Replace("", """")
End If

If str = "/CC" Then
_sendMail.SendCC = args(i + 1).Replace("", """")
End If

If str = "/BCC" Then
_sendMail.SendBCC = args(i + 1).Replace("", """")
End If

If str = "/Attachment" Then
_sendMail.AddAttachment(args(i + 1))
End If

If str = "/Trace" Then
_trace = True
End If

i = i + 1
Next
Lastly I created a "Try" statement to handle the sending of the email as well as some loging processes.  It is very important in development to add the ability to "trace" an application to help troubleshoot errors.  Within the "Try statment I check the _trace variable to see if the commandline had an argument to turn on tracing.  If it does then it will output all the values being send to the email process to the log file.  Next the process will call the function to send the email with the provided parameters.  If there is an issue with sending the email the the "Catch" portion of the statment will output the error to the log file and lastly the "Finaly" portion of the statement will clear and destroy any open references in the code.

Try

If _trace Then
trace = "SMTPServer=" & _sendMail.SMTPServer & ":"
trace &= "SMTPPort=" & _sendMail.SMTPPort & ":"
trace &= "SentTo=" & _sendMail.SendTo & ":"
trace &= "SentToName=" & _sendMail.SendToName & ":"
trace &= "SendFrom=" & _sendMail.SendFrom & ":"
trace &= "SendSubject=" & _sendMail.SendSubject & ":"
trace &= "SendBody=" & _sendMail.SendBody & ":"
trace &= "SendCC=" & _sendMail.SendCC & ":"
trace &= "SendBCC=" & _sendMail.SendBCC & ":"
trace &= Now.Date.ToString("yyyyMMdd") & " " & Now.TimeOfDay.ToString() & vbCrLf
writer.WriteLine(trace)
End If

_sendMail.Send()

Catch ex As Exception
trace = ex.Message & " - " & ex.StackTrace.ToString & vbCrLf
trace &= Now.Date.ToString("yyyyMMdd") & " " & Now.TimeOfDay.ToString() & vbCrLf
writer.WriteLine(trace)

Finally
If Not writer Is Nothing Then
writer.Flush()
writer.Close()
writer = Nothing
End If
End Try
End Sub
Click this link to download the vb file that I used in the project

Sunday, April 18, 2010

Who Are You - Your Personal Brand

Who are you…..?

Or more importantly who do you want others to perceive you to be. With the emergence of social media more and more of our lives are becoming visible to others. In some ways this is good and in other it has been disastrous.

Most people consider marketing something that only business need to be concerned with, though each of us have our own personal brand. Our personal brand is the person that others perceive us to be.

Historically most people’s personal brand encompassed first impressions and our résumé. In our current time where social media is a large part of our life our personal brand now encompasses many other elements; blogs, social forums, email addresses, web sites…. If we are not careful and do not plan our interactions carefully we could be creating a personal brand that is contrary to what we want it to be.

For the longest time I stayed out of the social media arena because I wanted to be careful not to harm my professional image with a lot of personal stuff that my employer, potential employer or clients do not need to know about. Recently I came to a realization that I am also hurting my personal image as much as I am protecting it. In essence if I am not visible in the social media arena I am reducing my visibility and my professional image only encompasses personal interaction and what others write about me. I finally started to get out there and did some research and planning so that I can be wise about my activities. I have made mistakes none of which have been embarrassing though they could have led that way if I was not already being a little shy about my interactions.

The first suggestion that I would make is to try to segment your personal and professional life as much as possible. This starts with your email address. Get a professional email address, one that is not tied to your internet service. Using your free accounts that come with your internet service is convenient though if you ever change your service it could cause issues with people wanting to connect with you professionally. Plus, by using those emails you are doing more marketing for your service provider than you are for yourself. Use an address that is professional. CutE85@hotmail.com is probably not a good representation of someone who wants to get into public office. Remember first impressions are extremely important and in these times potential employers my have more interaction with our email address than they do with us personally. Try to keep your professional and personal addresses different enough that if someone Google’s your professional email address they do not come up with your personal life as well.

Social networking sites can be important to building or destroying your personal brand. Be careful on what you post and who can see your posts. Don’t just befriend anyone that requests it. Make sure that they are people you know. You would not want a comment made by a “friend” to potentially cause you embarrassment to you professionaly. According to Melanie Gallegas (link) 8% of US companies have sacked social media miscreants. Whether you like it or not you represent the company you work for. If you list their name on your linkedin account, mention them on your Facebook page or wear their company logo and post a picture of it online then you represent them for good or bad. Following are a few examples of how poor choices in social media have affected other’s employment.

Stacy Snyder (story quoted from a myspace.com forum)

“In the absence of strong protections for employees, poorly chosen words or even a single photograph posted online in one’s off-hours can have career-altering consequences. Stacy Snyder, 25, who was a senior at Millersville University in Millersville, Pa., offers an instructive example. Last year, she was dismissed from the student teaching program at a nearby high school and denied her teaching credential after the school staff came across her photograph on her MySpace profile. She filed a lawsuit in April this year in federal court in Philadelphia contending that her rights to free expression under the First Amendment had been violated. No trial date has been set.”

Unknown Coke employee (quoted from an article by Janine Yancey)

“During the height of the cola wars in 2003, a Coke delivery driver was fired for sipping a Pepsi on the clock, while a Colorado man was fired in May 2005 from his job at a Budweiser distributor for a conflict of interest. The offending activity: he was spotted drinking Coors at a bar on Saturday night. His boss reportedly informed him that drinking the competitor's product was ‘putting food on the competitor's table, while we are putting food on yours.’”

Unknown Facebook User (paraphrased from a presentation done by Melanie Gallegos)

A Facebook user posted a comment about how she hated her job and that her bass was a “Wanker”. Unfortunately for her she did not remember that she had added her boss to her list of friends and he promptly responded that she did not need to report to work the next day.

A potential Cisco employee (quoted from an ABC New article by Dalia Fahmy)

“One Twitter user posted an update last year saying "Cisco just offered me a job! Now I have to weigh the utility of a fatty paycheck against the daily commute to San Jose and hating the work."

A Cisco employee responded, "Who is the hiring manager? I'm sure they would love to know that you will hate the work. We here at Cisco are versed in the Web."

Needless to say, the applicant did not end up working at Cisco.”

On the other hand your social media presence can work for you. The other day I was in a training session for a product called SharePoint from Microsoft. During the meeting the trainer had commented that if we wanted to know more about a specific topic that we should check out a person’s website (to be honest I forgot her name and did not write it down). She was not an employee of Microsoft. She is just considered an expert on that platform as a result of her social media interactions. She has made a name for herself doing nothing more than blogging about helpful hints and learned best practices that she has come across.

Another example is from one of my favorite authors, Brandon Sanderson. Not too long ago another one of my favorite authors, James Rigney (AKA Robert Jordan) had passed away. Sanderson had posted a blog about Rigney’s influence in his life and how it helped to give him direction in his current profession as a Science Fiction writer. The message that he wrote was very touching. So much that Rigney’s widow, Harriet, had somehow got a hold of this note and later contacted Sanderson to finish Rigney’s legacy in writing the final book (later to become three books) of the Wheel of Time series. The fact that Sanderson is a wonderful writer also playing into her decision I am sure.

After hearing about these stories you may be thinking, “Hey we live in a country where we have free speech and should be able to say what we want to say.” That is true though that free speech can still have negative impacts. Whether you like it or not you represent your company and employers or potential employers will not want to be associated with anyone that could do their brand harm. They may not come out and say that you did not get hired, did not get promoted or did not get the desired raise because of your social media interactions but that does not mean it did not happen and they found another reason to disguise it. By all means use your rights to free speech though do it in a way that it does not mar those that you professionally represent.

It is important for you to take control of your personal brand and control the parts of it that you want your professional network to see. Businesses do this all the time through the use of SEO and SEM. Take control of your personal brand and how your professional network perceived you. Gallegos mentioned in her presentation some elements that I am going to expand upon that you should consider in planning and implementing your personal brand.

  • Come up with a “keyword”; your full name, nickname, married name or “handle” that you want to own and stick to it.

This is especially important if you have a common name. I have a very common name. In fact if you were to Google my name the chance of getting any info about me is next to impossible. Most likely your first hits will be regarding the Robert Ford that killed Jesse James. If you use something other than your name, make sure it is something professional and represents your personal brand. “The Tan Queen” would not be a good nickname to use for someone who wants to be a network administrator.

  • Buy a domain and build a website of blog.

If possible have a domain name that matches your “keyword”. Also make sure that the content is appropriate. Expressing you thoughts about a drunken party the previous evening on your Small Business Technology blog would not set the right tone. Also, if you are trying to promote yourself as a web designer please have a decent website. I was involved in a situation where I was helping a friend find a web designer for his small business. He did not have enough to pay for a big company to do it so we were looking at some independent developers. I was sadly disappointed by the number of people who were promoting their services and had terrible websites themselves. Make sure that if you profess a certain profession or skill set that it can be backed up by what people can see.

  • Use an email address from your professional domain as your email address for all professional correspondence.

Do not use your personal email address for professional use. It will make it too easy for personal interactions to become professional correspondence. If you use social networking sites like MySpace, Facebook, Twitter… have a profile associated to your personal email and another for your professional email. Yes that will make it a pain to manage though it can save you some potential embarrassments in the future. Also if you have a smart phone where you keep your social networking sites logged in at all times have it connected to your personal account. You do not want the boss to know that you are out golfing with a buddy when you are supposed to be at home sick.

  • Link all of your professional networking sites together using your “keyword” and with links to your profile.

An example: Recently I have started writing articles for one of my favorite websites, CodeProject (though I only have two articles up there as of yet). On my profile for that website, I added a link to my LinkedIn profile. My LinkedIn profile has a link to my Facebook profile. My Facebook profile has a link to my CodeProject profile. And all three have links to my technology blog. All of these accounts I have associated to the same email address that I use for all of my professional interactions.

  • Blog positioning your credibility, personality or expertise/thought leadership.

If you blog make sure that your blogs are relevant to your personal brand. Show that you know what you are talking about and that you are a leader or expert in that field. Don’t spend time talking about how great you are. No body likes personal aggrandizements. Be humble and let your work speak for itself. Make sure to keep confidential information out of your blogs. Hackers and corporate pirates constantly look at social media to find info that can help them to steal or get an edge of other businesses. Many times you will see a system admin posting a specific problem that they encountered and put too much detail in to the note and gave someone all the info that they would need to hack into the company’s website. If you pick up any “how-to” book in hacking the first think it will recommend is to check help groups and blogs to get info that can help to hack the network.

  • Consistency.

People like others that they can rely on. If you are a blogger and you really want to build your brand through that medium then you need to blog about relevant info and often. If you only post a blog once every three months or are inconsistent on your schedule then others will not know when to check out your blog and may lose interest. This is something that I am not good at and plan to get better at. Keep your websites up-to-date and relevant. If you are a hardware specialist then having how-tos relating to fixing a IBM 386 is not going to help you.

  • Never assume that anything you post is private

Even on your personal profiles if you assume that anything you post is public even though you have your privacy options set and act accordingly then you will be pretty safe.

  • Be aware of who you befriend

Don’t just accept anyone as your friend. Remember that your “friends” also represent you. If you befriend your college buddy’s personal profile on your professional profile and someone in your professional network checks out their page and sees pictures of you dancing on a table after a weekend of dubious behavior the damage is almost as bad as if you posted it on your profile directly. Make sure that your friends understand what that profile is for and act accordingly.

  • Be thoughtful about what you put in writing.

Sometimes we are in a hurry to put out a post and put it together quickly to get it out. Make sure that you use spell check and that your grammar is decent. You do not want people to think that you could not handle yourself in a conversation with important people. Also if you are going to quote something provide a reference or link to the information to help provide credibility. In fact there is value in doing so. Links to other sites helps you in regards to search engine optimization. In fact if you reference someone and provide some decent information it could not hurt to send that person a note about it in hopes that they might also link to you in order to drive more traffic and build your name faster.

  • When corresponding with others, be diplomatic and engaging.

Never use harsh words or disparaging comments to criticism someone’s words or work. It only makes you look like the fool and may detract from others wanting to associate with you in fear that you might do the same to them. Also it could get you banned from certain sites which would hurt you in your ability to build your brand.

  • Include social media elements in your résumé.

If you include your professional website, blogs, email and such in your résumé you will helping to direct potential employers where you want them to go. They will be less likely to Google you and come up with things that you do not want them to see. Not only will this help direct them where you want them to go it can help to show more of your expertise and leadership that it not possible to show in a one or two page résumé.

  • Professional logo.

Use an appropriate photo. You should be dressed appropriately and it should be of you. Your pictures of your kids are cute and all but your professional network wants to know about you not your kids.

  • Monitor your personal brand

Make sure that you know what others are saying about you. Google” your “keywords” often to make sure that you are still presenting the personal image that you want to portray. If something negative comes up work to resolve it quickly so that you can reduce any potential issues it could cause. It is true that you can delete comments placed on your Facebook wall though if you get to it after you boss or potential client has already seen it then the damage is already done. Do not allow others to post comments on your social networking sites message boards. You cannot control what they will write and you will be opening yourself up to a potential risk.

  • Don’t participate in bad mouthing your employer

Not only could it potentially lead to being black listed or termination in your current employment it could lead prevent you from getting hired somewhere else. Potential employers would be hesitant to bring you on in fear that you would do the same about them. You will be considered damaged goods. Instead of focusing on the bad things about your job, focus on the good things. If there are no good things then do not say anything, just quit and find somewhere else to work. There are a lot of companies out there. If that is not an option then see if there is anything you can do to help make the situation better. If you are allowed to help bring about change, not only would it help to make you happier but is would look great on a résumé.

Remember that everything you do is a potential impact on your personal brand. You want those things that are positive to be in the forefront. Take time to plan out how you want other to perceive you. If you are not sure yet at least lay the ground work so that when you are ready you can make the move without much work. Some sites do not allow the changing of email accounts and you do not want to get locked into something that would not enhance your personal brand.

References:

http://www.christopherspenn.com/2010/04/02/why-personal-brand-is-essential-to-corporate-marketing-success/

http://forum.myspace.com/index.cfm?fuseaction=messageboard.viewThread&entryID=49711567&groupID=100472090

http://www.salesandmarketing.com/msg/content_display/training/e3i111888fc4afd5a6a15a93bde975fac05

http://www.slideshare.net/gearyinteractive/social-media-for-employment-2020310

http://abcnews.go.com/Business/PersonalFinance/facebook-firings-employees-online-vents-twitter-postings-cost/story?id=9986796

http://www.odesk.com/blog/2009/07/facebook-faux-pas-what-not-to-do-in-social-network-view/