Twilio SMS + hMailServer

Use this forum if you have problems with a hMailServer script, such as hMailServer WebAdmin or code in an event handler.
Post Reply
palinka
Senior user
Senior user
Posts: 4455
Joined: 2017-09-12 17:57

Twilio SMS + hMailServer

Post by palinka » 2022-06-04 16:32

I moved my server from a physical box at home to a rented VPS. I had a physical modem connected to send SMS messages via GammuSMS, which worked great. I get automated notifications for things I want to see from hmailserver triggers and I have some scripts for other stuff like email2sms. Anyway, I can't connect my modem to the VPS, so I looked around for a substitute and found Twilio. They do a bunch of stuff like voice and other stuff. I'm only interested in SMS. It costs less than $0.01 per message + $1/month for the line fee. Pretty cheap. Maybe even cheaper than the $10/month that the physical SIM cost me. Of course, the SIM price is fixed and Twilio is variably priced, but looking at my volume it should end up costing around the same or maybe slightly less.

Anyway, I needed to connect to Twilio in order to send messages, of course, so I came up with this script.

EventHandlers.vbs:

Code: Select all

Private Const TwilioSID = "yourTwilioSID"
Private Const TwilioToken = "yourTwilioToken"
Private Const TwilioSMSFrom = "+12125551212" ' Your Twilio SMS from number

Function oLookup(strRegEx, strMatch, bGlobal)
	If strRegEx = "" Then strRegEx = StrReverse(strMatch)
	With CreateObject("VBScript.RegExp")
		.Pattern = strRegEx
		.Global = bGlobal
		.MultiLine = True
		.IgnoreCase = True
		Set oLookup = .Execute(strMatch)
	End With
End Function

Function jsonDecode(jsonString)
    Dim oSCtrl
    Set oSCtrl = CreateObject("ScriptControl")  ' Required: https://tablacus.github.io/scriptcontrol_en.html
    oSCtrl.Language = "JScript"
    Set jsonDecode = oSCtrl.Eval("(" & jsonString & ")")
End Function

Function RemoveHTML(strHTML)
	' .Pattern = "(<style[\s\S]*?style>)|(\/\*[\s\S]*?\*\/)|(<[\s\S]*?>)"
	With CreateObject("VBScript.RegExp")
		.Pattern = "<[^>]+>|&nbsp;|&lt;|&gt;|&quot;|&amp;|\s{2,}|(v|o|w)\\\:\*|\.shape|\{behavior:url\(\#default\#VML\)\;\}"
		.Global = True
		.MultiLine = True
		.IgnoreCase = True
		RemoveHTML = .Replace(strHTML, " ")
	End With
End Function

Function SendSMS(SMSNumber, sMSG)
	Dim rc, WshShell, strRegEx, Match, Matches, sMSGLen, Url, Request, postData, oResponse

	If SMSNumber = Empty Then SMSNumber = "3475559876" ' Change this to YOUR mobile number

	sMSG = Replace(sMSG, "<", "(")
	sMSG = Replace(sMSG, ">", ")")
	sMSG = RemoveHTML(sMSG)
	sMSG = Replace(sMSG, Chr(34), "\" & Chr(34))

    REM - replace line breaks
	strRegEx = "(\r\n|\r|\n)"
	Set Matches = oLookup(strRegEx, sMSG, False)
	For Each Match In Matches
	   sMSG = Replace(sMSG, Match.Value, " ")
	Next
	
	REM - delete google calendar note
	strRegEx = "(-::~.+~::-)"
	Set Matches = oLookup(strRegEx, sMSG, False)
	For Each Match In Matches
	   sMSG = Replace(sMSG, Match.Value, " ")
	Next

	REM - replace double/multiple spaces
	strRegEx = "([\s]{2,})"
	Set Matches = oLookup(strRegEx, sMSG, False)
	For Each Match In Matches
	   sMSG = Replace(sMSG, Match.Value, " ")
	Next

	sMSGLen = len(sMSG)

	Set Request = CreateObject("MSXML2.ServerXMLHTTP.6.0")
	Url = "https://api.twilio.com/2010-04-01/Accounts/" & TwilioSID & "/Messages.json"
	Request.Open "POST", Url, False, TwilioSID, TwilioToken
	Request.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
	postData = "From=" & TwilioSMSFrom & "&To=%2B1" & SMSNumber & "&Body=" & sMSG
	Request.send postData
	Set oResponse = jsonDecode(Request.responseText)

	If (oResponse.status <> "queued" ) Then
		EventLog.Write( "================== SMS ==================" )
		EventLog.Write( ":Status           : " & Request.status )
		EventLog.Write( ":Error Code       : " & oResponse.code )
		EventLog.Write( ":Message          : " & oResponse.message )
		EventLog.Write( ":More Info        : " & oResponse.more_info )
		EventLog.Write( "=========================================" )
	Else
		EventLog.Write( "================== SMS ==================" )
		EventLog.Write( ":Status           : " & Request.status )
		EventLog.Write( ":Recipient Number : " & oResponse.to )
		EventLog.Write( ":Message          : " & oResponse.body )
		EventLog.Write( ":Segments         : " & oResponse.num_segments )
		EventLog.Write( "=========================================" )
	End If

End Function

Sub OnAcceptMessage(oClient, oMessage)

	Dim sMSG, SMSNumber

	' Will send SMS message to default recipient
	sMSG = "Notification: " & oMessage.FromAddress & " sent a message to " & oMessage.Recipients(0).OriginalAddress
	Call SendSMS(SMSNumber, sMSG)

	' Will send SMS message to 6465554321
	SMSNumber = "6465554321"
	sMSG = "Notification: " & oMessage.FromAddress & " sent a message to " & oMessage.Recipients(0).OriginalAddress
	Call SendSMS(SMSNumber, sMSG)

End Sub

One thing to note: If you're not sending primarily to mobile numbers in North America, you'll need to delete the "1" in line 71 above.

Change:

Code: Select all

	postData = "From=" & TwilioSMSFrom & "&To=%2B1" & SMSNumber & "&Body=" & sMSG
To:

Code: Select all

	postData = "From=" & TwilioSMSFrom & "&To=%2B" & SMSNumber & "&Body=" & sMSG
Also note that additional script control software is required for Function jsonDecode: https://tablacus.github.io/scriptcontrol_en.html (Thanks, Soren!)

Post Reply