-
by Kamal A. Mehdi
Description
This sample code demonstrates how to use the Winsock control shipped with Visual Basic to send an email message through an SMTP (Simple Mail Transport Protocol) server. The sample code makes a connection with the SMTP remote host via TCP on port 25 and sends the email message data containing the sender name, sender email address, recipient name, recipient email address, message subject, and the message body text. It checks for the appropriate response code to be sent by the SMTP server in each data-segment transmission to verify that data is correctly received by the server.
The core of the code is represented by the SendEmail procedure, which is explained later in detail. The sample code will only send simple text email messages to SMTP mail servers; no attachments are possible.
Syntax
SendEmail(MailServerName, SenderName, SenderEmail, RecipientName,
ËRecipientEmail, EmailSubject, EmailBody)
Part Description
--------------------------------------------------------------------------------
MailServerName Required. A string expression specifying the name of the SMTP server.
SenderName Required. A string expression specifying the name of the email sender.
SenderEmail Required. A string expression specifying the email address of the sender.
RecipientName Required. A string expression specifying the name of the email recipient.
RecipientEmail Required. A string expression specifying the email address of the recipient.
EmailSubject Required. A string expression specifying the email message subject.
EmailBody Required. A string expression specifying the body of the message text.
--------------------------------------------------------------------------------
Modules and Controls Required
Module/Control Description
--------------------------------------------------------------------------------
Form1 A standard non-MDI Visual Basic form (.FRM) with the Caption property set to Send E-Mail Using the Winsock Control
Winsock1 A Winsock control
Command1 A command button with the Caption property set to &Send E-Mail
Command2 A command button with the Caption property set to &Exit
StatusLabel A label control with the Caption property set to gh
Frame1 A frame control with the Caption property set to Status:
Text1() A control array of seven text boxes with the Text1(6) MultiLine property set to True
Label1() A control array of seven label controls with the Caption property set as shown:
Index = Caption
0 = Your Name
1 = From (Your e-mail address)
2 = Recipientfs Name
3 = To (Recipientfs e-mail address)
4 = E-Mail (SMTP) server Name
5 = Subject
6 = Message Body
--------------------------------------------------------------------------------
Follow these steps to draw controls:
1. Start a new standard EXE project. Form1 is created by default. Set the formfs Height and Width properties to approximately 6100 and 7200, respectively, and set its Caption property as shown earlier in this section.
2. Draw Label1 on the top-left side of the form. Create the other six label control array elements from the label control and position them under Label1(0) so that they are arranged according to their Index property value (0, 1,..., 6 from top to bottom). Set the Caption property of each of the label control array elements as shown earlier.
3. Draw Text1 to the right of Label1(0). Create the other six text box control array elements from the text box and position them to the right of each label control created in step 2, with each text box to the right of the label control that has the same Index property value. Adjust the width of all text boxes so that they extend up to the right edge of the form. Adjust the height of the last text box (Text1(6)) so that it can accommodate multiple lines, and set its MultiLine property to True.
4. Draw Command1 and Command2 command buttons under Text1(6) and set their Caption properties as shown earlier.
5. Draw Frame1 below the command buttons and set its Caption property as shown earlier.
6. Draw the StatusLabel label control inside Frame1, and adjust its size so that it fills the entire frame area.
7. Draw the Winsock1 Winsock control anywhere on the form.
--------------------------------------------------------------------------------
Note
The Winsock control is not included on the toolbox by default. You can add it to the toolbox by selecting the Components submenu from the Project menu and adding the control.
You can create control arrays by inserting one control on the form and copying and pasting the control on the form using either the right mouse button or the Edit menu. When you paste the control on the form, Visual Basic will prompt you whether to create a control array; choose Yes.
--------------------------------------------------------------------------------
Code Listing
eGeneral form declarations
Dim Response As String
Sub SendEmail(MailServerName As String, SenderName As String,
Ë SenderEmailAddress As String, RecipientName As String,
Ë RecipientEmailAddress As String, EmailSubject As String,
Ë EmailBodyOfMessage As String)
eDeclare variables
Dim Data1 As String, Data2 As String
Dim Data3 As String, Data4 As String
Dim Data5 As String, Data6 As String
Dim Data7 As String, Data8 As String
Dim CurrentDate As String
Dim TimeDifference As String
eSet the Winsock controlfs local port to 0, because otherwise
eyou may not be able to send more than one e-mail message
eevery time the program runs
Winsock1.LocalPort = 0
eStart composing the required data strings, but first check
eif the Winsock socket is closed
If Winsock1.State = sckClosed Then
eCompose the current date and time string
TimeDifference = g -200h eYour zone time-difference
CurrentDate = Format(Date, gDddh) & g, g & Format(Date, gdd Mmm YYYYh)
Ë& g g & Format(Time, ghh:mm:ssh) & TimeDifference
eSet the program name used to send this e-mail message (you can
eput your program name here)
AppName = gX-Mailer: g + gMy Mail Program V1.0h + Chr(13) + Chr(10)
eSet the e-mail address of the sender
Data1 = gmail from:h + Chr(32) + SenderEmailAddress + Chr(13) +
ËChr(10)
eSet the e-mail address of the recipient
Data2 = grcpt to:h + Chr(32) + RecipientEmailAddress + Chr(13) +
ËChr(10)
eSet the date string
Data3 = gDate:h + Chr(32) + CurrentDate + Chr(13) + Chr(10)
eSet the name of the sender
Data4 = gFrom:h + Chr(32) + SenderName + Chr(13) + Chr(10)
eSet the name of the recipient
Data5 = gTo:h + Chr(32) + Text1(2) + Chr(13) + Chr(10)
eSet the subject of the E-Mail message
Data6 = gSubject:h + Chr(32) + EmailSubject + Chr(13) + Chr(10)
eSet the E-mail message body string
Data7 = EmailBodyOfMessage + Chr(13) + Chr(10)
eCombine the whole string for proper SMTP syntax
Data8 = Data4 + Data3 + AppName + Data5 + Data6
eSet the Winsock protocol
Winsock1.Protocol = sckTCPProtocol
eSet the remote host name (of SMTP server)
Winsock1.RemoteHost = MailServerName
eSet the SMTP Port to the default port 25
Winsock1.RemotePort = 25
eStart the connection
Winsock1.Connect
eWait for response from the remote host
WaitForResponse (g220h)
eReport status
StatusLabel.Caption = gConnecting....h
StatusLabel.Refresh
eSend your computer name or company name
Winsock1.SendData (gHELO mycomputernameh + Chr(13) + Chr(10))
eWait for response from the remote host
WaitForResponse (g250h)
eUpdate status
StatusLabel.Caption = gConnectedh
StatusLabel.Refresh
eSend the first string
Winsock1.SendData (Data1)
eUpdate status
StatusLabel.Caption = gSending Messageh
StatusLabel.Refresh
eWait for response from the remote host
WaitForResponse (g250h)
eSend the second string
Winsock1.SendData (Data2)
eWait for response from the remote host
WaitForResponse (g250h)
eTell the SMTP server that you want to send data now
Winsock1.SendData (gdatah + Chr(13) + Chr(10))
eWait for response from the remote host
WaitForResponse (g354h)
eSend the data
Winsock1.SendData (Data8 + Chr(13) + Chr(10))
Winsock1.SendData (Data7 + Chr(13) + Chr(10))
Winsock1.SendData (g.h + Chr(13) + Chr(10))
eWait for response from the remote host
WaitForResponse (g250h)
eSend quitting acknowledgment
Winsock1.SendData (gquith + Chr(13) + Chr(10))
eUpdate status
StatusLabel.Caption = gDisconnectingh
StatusLabel.Refresh
eWait for response from the remote host
WaitForResponse (g221h)
eClose the connection
Winsock1.Close
Else
eReport error
MsgBox (Str(Winsock1.State))
End If
End Sub
Sub WaitForResponse(ResponseCode As String)
Dim Start As Single
Dim TimeToWait As Single
Start = Timer
eStart a loop checking for response from SMTP host
While Len(Response) = 0
TimeToWait = Start - Timer
DoEvents
eIf TimeToWait expires, report timeout error
If TimeToWait > 50 Then
MsgBox gSMTP timeout error, no response receivedh, 64, App.Title
Exit Sub
End If
Wend
While Left(Response, 3) <> ResponseCode
DoEvents
If TimeToWait > 50 Then
eReport error if incorrect code is received
MsgBox gSMTP error, improper response code received!h + Chr(10) +
ËhCorrect code is: g + ResponseCode + g, Code received: g +
ËResponse, 64, App.Title
Exit Sub
End If
Wend
eSet response to nothing
Response = gh
End Sub
Private Sub Command1_Click()
eCall the SendEmail procedure and pass the arguments: MailServerName,
e SenderName, SenderEmailAddress, RecipientName, RecipientEmailAddress,
e EmailSubject, EmailBodyOfMessage)
SendEmail Text1(4), Text1(0), Text1(1), Text1(2), Text1(3), Text1(5),
ËText1(6)
eUpdate status
StatusLabel.Caption = gMail Senth
StatusLabel.Refresh
End Sub
Private Sub Command2_Click()
Unload Me
End Sub
Private Sub Form_Unload(Cancel As Integer)
Set Form1 = Nothing
End
End Sub
Private Sub Winsock1_DataArrival(ByVal bytesTotal As Long)
eCheck for response from the remote host
Winsock1.GetData Response
End Sub
Enter the code into the appropriate form or control events as indicated, and run the project. Fill the text boxes with the appropriate data and click the Send E-Mail button. Watch the status label for the email session progress.
Analysis
The SendEmail procedure uses the Winsock control to send a simple plain text email message to an SMTP mail server. The use of the procedure is simple: you just need to send the necessary email message data as arguments, including the sender name, sender email address, recipientfs name and email address, and the email message subject and body text.
The SendEmail procedure starts the email session by composing the necessary email message data segments, initializing the Winsock control, connecting to the SMTP remote server, sending the senderfs and recipientfs email addresses, transferring the message data, and disconnecting from the remote server and closing the session. In each step of the email session, the SendEmail procedure calls another procedure, WaitForResponse, which checks the response code received from the remote server to verify whether the response is correct.
While the SendEmail procedure sends the email message, it updates a status label with the progress of the entire process. It reports the status when it first starts to connect to the remote host, when it gets connected, when the message is successfully sent, and when it disconnects. It also displays a message box when an error occurs during the email transfer process, such as a server reply time out, incorrect response code received from the SMTP server, and so on. It also displays a message box if the user tries to send an email while the Winsock socket is still open from a previous email session.
-
Great code! Where did you get the documentation of SMTP that you needed to write this code???
-
Kamal
Using the word "code" within brackets as a tag will format
your code like the VB editor. Using "/code" within brackets
will end the coding tag.
[code]
Your code goes here
[/code]
[Edited by dsy5 on 08-12-2000 at 06:45 PM]
-
Easier to Read
Is there away of doing this with out having to use the Winsock control? I would like to make this a separate sub so that I can call it from other functions but then I need a blank form to do it.
Thanks
This is easier to read then the original post.
Code:
Option Explicit
Dim Response As String
Private Sub cmdOriginal_Click(Index As Integer)
Call SendMail
End Sub
Sub SendMail()
Dim AppName As String
Dim Data1 As String
Dim Data2 As String
Dim Data3 As String
Dim Data4 As String
Dim Data5 As String
Dim Data6 As String
Dim Data7 As String
Dim Data8 As String
Dim CurrentDate As String
Dim TimeDifference As String
'Set the Winsock control's local port to 0, because otherwise
'you may not be able to send more than one e-mail message
'every time the program runs
Winsock1.LocalPort = 0
'Start composing the required data strings, but first check
'if the Winsock socket is closed
If Winsock1.State = sckClosed Then
'Compose the current date and time string
TimeDifference = " -200" 'Your zone time-difference
CurrentDate = Format(Date, "Ddd") & ", " & Format(Date, "dd Mmm YYYY") & " " & _
Format(Time, "hh:mm:ss") & TimeDifference
'Set the program name used to send this e-mail message (you can
'put your program name here)
AppName = "X-Mailer: " & "My Mail Program V1.0" & vbCrLf
'Set the e-mail address of the sender
Data1 = "mail from:" & Chr(32) & "[email protected]" & vbCrLf
'Set the e-mail address of the recipient
Data2 = "rcpt to:" & Chr(32) & "[email protected]" & vbCrLf
'Set the date string
Data3 = "Date: " & Chr(32) & CurrentDate & vbCrLf
'Set the name of the sender
Data4 = "From: " & Chr(32) & "Senders Name" & vbCrLf
'Set the name of the recipient
Data5 = "To: " & Chr(32) & "Recipient Name" & vbCrLf
'Set the subject of the E-Mail message
Data6 = "Subject: " & Chr(32) & "Test Subject" & vbCrLf
'Set the E-mail message body string
Data7 = "Body of message" & vbCrLf
'Combine the whole string for proper SMTP syntax
Data8 = Data4 & Data3 & AppName & Data5 & Data6
'Set the Winsock protocol
Winsock1.Protocol = sckTCPProtocol
'Set the remote host name (of SMTP server)
Winsock1.RemoteHost = "mail.smtp.server.com"
'Set the SMTP Port to the default port 25
Winsock1.RemotePort = 25
'Start the connection
Winsock1.Connect
'Wait for response from the remote host
WaitForResponse ("220")
'Send your computer name or company name
Winsock1.SendData ("HELO Your Computer Name" & vbCrLf)
'Wait for response from the remote host
WaitForResponse ("250")
Winsock1.SendData (Data1)
WaitForResponse ("250")
Winsock1.SendData (Data2)
WaitForResponse ("250")
'Tell the SMTP server that you want to send data now
Winsock1.SendData ("data" & vbCrLf)
'Wait for response from the remote host
WaitForResponse ("354")
'Send the data
Winsock1.SendData (Data8 & vbCrLf)
Winsock1.SendData (Data7 & vbCrLf)
Winsock1.SendData ("." & vbCrLf)
'Wait for response from the remote host
WaitForResponse ("250")
'Send quitting acknowledgment
Winsock1.SendData ("quit" & vbCrLf)
'Wait for response from the remote host
WaitForResponse ("221")
'Close the connection
Winsock1.Close
Else
'Report Error
MsgBox (Str(Winsock1.State))
End If
End Sub
Sub WaitForResponse(ResponseCode As String)
Dim Start As Single
Dim TimeToWait As Single
Start = Timer
'Start a loop checking for response from SMTP host
While Len(Response) = 0
TimeToWait = Start - Timer
DoEvents
'If TimeToWait expires, report timeout error
If TimeToWait > 50 Then
MsgBox "SMTP timeout error, no response received", 64, App.Title
Exit Sub
End If
Wend
While Left(Response, 3) <> ResponseCode
DoEvents
If TimeToWait > 50 Then
'Report error if incorrect code is received
MsgBox "SMTP error, improper response code received!" & Chr(10) & _
"Correct code is: " & ResponseCode & ", Code received: " & _
Response, 64, App.Title
Exit Sub
End If
Wend
'Set response to nothing
Response = ""
End Sub
Private Sub Winsock1_DataArrival(ByVal bytesTotal As Long)
'Check for response from the remote host
Winsock1.GetData Response
End Sub
-
Does anyone know how to use the code above to send to multiple email address? I know this will work to send just to one person but what if you want to send 20 people the same message??
-
Have a loop and send it to people in a list.
-
I have an error in
Winsock1.LocalPort = 0
Or in all comands with Winsock1.
Why?
The error is Object NEcessary
Tanks
-
Whats a SMTP Server address that I can use???
-
wmplollo - you need a winsock control on your form.
Pc_Madness - try mail.hotmail.com