.NET Programming With Me

VB.NET: Sending SMS through a desktop application

Most SMS gateway providers expose a simple HTTP REST API: you POST a form-encoded payload with your sender address, recipient number, and message body, and the gateway delivers the SMS. This post shows how to wire that up in VB.NET using HttpWebRequest, including Basic authentication and error handling for protocol-level failures.

The endpoint and credentials below are placeholders. Substitute the URL, username, and password supplied by your own gateway provider. The structure of the request is the same across most providers that use form-encoded POST APIs.

The SendSMS subroutine

The subroutine accepts a sender number, a recipient number, and the message text. It builds a form-encoded POST body, attaches a Basic Authorization header using the gateway credentials, writes the body to the request stream, and shows a confirmation or error message depending on the response.

Sub SendSMS(ByVal FromNumber As String, ByVal ToNumber As String, ByVal message As String)
    Try
        'SMSified API endpoint
        'the url is given by the gateway provider
        webTarget = "http://api.xyz.com/"

        'Parameters to send with API request
        post_data = "address=" & ToNumber & "&senderaddress=" & FromNumber & "&message=" & HttpUtility.UrlEncode(message)

        'Create New HTTP Request
        request = DirectCast(WebRequest.Create(webTarget), HttpWebRequest)
        request.Method      = "POST"
        request.ContentType = "application/x-www-form-urlencoded"

        Dim byteArray As Byte() = Encoding.ASCII.GetBytes(String.Format(post_data, "14075551212", "This is a test from VB.nET"))
        request.ContentLength = byteArray.Length

        'Set HTTP authorization header
        'authUser holds the username whereas authPassword for password given by the gateway provider
        Dim authInfo As String = authUser & ":" & authPassword
        authInfo = Convert.ToBase64String(Encoding.Default.GetBytes(authInfo))
        request.Headers("Authorization") = "Basic " & authInfo

        'Send HTTP Request
        Dim PostStream As Stream = request.GetRequestStream()
        PostStream.Write(byteArray, 0, byteArray.Length)
        response = request.GetResponse()

        MessageBox.Show("Message Successfully Sent", "", MessageBoxButtons.OK, MessageBoxIcon.Information)

    Catch ex As WebException
        If ex.Status = WebExceptionStatus.ProtocolError Then
            Dim resp As WebResponse    = ex.Response
            Dim sr   As StreamReader   = New StreamReader(resp.GetResponseStream())
            MessageBox.Show(sr.ReadToEnd(), "SMS", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End If

    Catch ex As Exception
        ShowException(ex.GetType().ToString(), ex.Message)
    End Try
End Sub

Calling the subroutine

Once the subroutine is in place, sending a message is a single line. Pass the sender number assigned by your provider, the destination number, and the message text:

SendSMS("FromNumber", "ToNumber", "Your message body here")

Where FromNumber is the originating number assigned to you by the gateway provider, ToNumber is the recipient's number in the format your provider expects (typically E.164, such as +14075551234), and the third argument is the message body.


What each part does

A few points worth understanding before plugging this into a real application:

  • Form-encoded body: The payload is built as a URL-encoded query string and written to the request stream as raw bytes. HttpUtility.UrlEncode on the message text ensures that spaces, ampersands, and special characters in the message body do not break the parameter parsing on the gateway side.
  • Basic authentication: The credentials are concatenated as username:password, Base64-encoded, and sent in the Authorization header. This is the standard Basic auth scheme. Note that Basic auth over plain HTTP exposes credentials in transit; always use an HTTPS endpoint in production.
  • Protocol error handling: The WebException catch block checks specifically for ProtocolError, which covers HTTP 4xx and 5xx responses. Reading the response body from ex.Response in that branch gives you the error detail the gateway returned, which is far more useful than the generic exception message alone.
Note: HttpWebRequest is the legacy HTTP client in .NET. If you are on .NET 5 or later, even in a VB.NET project, HttpClient is the preferred replacement. It supports async/await natively, reuses connections across calls, and avoids the socket exhaustion issues that can occur when HttpWebRequest instances are created and discarded frequently.
Found this useful? Drop a comment below if you have a variation or ran into an edge case I did not cover.