HI all.
I am working on some code to send/receive SMS messages through Zeep Mobile (http://zeepmobile.com/developers/).
I have looked at their google groups and even contacted their support but they've not been very good at communicating back and I am really flying blind now.
I have to get integrated with them (work has required it) and I'm not sure why my code is not working. So, I'm wondering if anyone out there has any C# .Net code that they won't mind sharing so that I may integrate that into my app.
Of course, this is all dependent on whether you have experience with Zeep or not. If you want me post my code, I can do that too. Let me know.
Thanks and I really appreciate the help.
**
**
Please forgive the sloppy code. Its just something I threw together to test Zeep and I'm hoping someone can give it a shot. (.Net 3.5 console app in case you want to build it).
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Net.Security;
using System.Web;
using System.Web.Handlers;
using System.IO;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
namespace ConsoleApplication1
{
class Program
{
public static string API_KEY = "MY_API_KEY";
public static string SECRET_ACCESS_KEY = "MY_SECRET_KEY";
public static string PATTERN_RFC1123 = "ddd, dd MMM yyyy HH:mm:ss " + "GMT";
static void Main(string[] args)
{
// URL for sending message -
// send_message = "https://api.zeepmobile.com/messaging/2008-07-14/send_message";
// blast_message = "https://api.zeepmobile.com/messaging/2008-07-14/blast_message";
string apiurl = "https://api.zeepmobile.com/messaging/2008-07-14/blast_message";
// FORMAT must be Sun, 06 Nov 1994 08:49:37 GMT
string http_date = DateTime.UtcNow.ToString("r");
// Text to send
string body = HttpUtility.UrlEncode("Test message.", System.Text.Encoding.UTF8);
// NOTE: Use 'user_id=22&body=' instead of just 'body=' when sending a message to a user.
// 22 is a user I have previously registered with ZEEP and is used for testing purposes.
string parameters = "body=" + body;
// String that will be converted into a signature.
string canonicalString = API_KEY + http_date + parameters;
//------------START HASH COMPUTATION---------------------
// Compute the Base64 HMACSHA1 value
HMACSHA1 hmacsha1 = new HMACSHA1(SECRET_ACCESS_KEY.ToByteArray());
// Compute the hash of the input file.
byte[] hashValue = hmacsha1.ComputeHash(canonicalString.ToByteArray());
String b64Mac = hashValue.ToBase64String();
String authentication = String.Format("Zeep {0}:{1}", API_KEY, b64Mac);
//-----------END HASH COMPUTATION------------------------
// We are using TCPClient instead of an HTTPWebRequest because we need to manually
// set the "Headers" such as Date, Authorization etc which cannot easily be done with HTTPWebRequest.
Uri reqUrl = new Uri(apiurl);
TcpClient client = new TcpClient(reqUrl.Host, reqUrl.Port);
NetworkStream netStream = client.GetStream();
// SSLStream is used for secure communication. ZEEP requires the use of SSL to send and SMS.
System.Net.Security.SslStream sslStream = new System.Net.Security.SslStream(
netStream,
false,
new System.Net.Security.RemoteCertificateValidationCallback(ValidateServerCertificate));
sslStream.AuthenticateAsClient(reqUrl.Host);
// POST content we are going to transmit over the SSL channel.
// See. http://zeepmobile.com/developers/documentation/messaging/2008-07-14/rest_api#send_message
System.IO.StreamWriter s = new System.IO.StreamWriter(sslStream);
s.WriteLine(String.Format("POST {0} HTTP/1.1", "/api/blast"));
s.WriteLine(String.Format("Host: {0}", "api.zeepmobile.com"));
s.WriteLine(String.Format("Authorization: Zeep {0}:{1}", API_KEY, b64Mac));
s.WriteLine(String.Format("Date: {0}", http_date));
s.WriteLine(String.Format("Content-Type: {0}", "application/x-www-form-urlencoded"));
s.WriteLine(String.Format("Content-Length: {0}", parameters.Length));
s.WriteLine(String.Format("{0}", parameters));
s.Flush();
System.IO.StreamReader r = new StreamReader(sslStream);
string resp = r.ReadToEnd();
Console.WriteLine(resp);
r.Close();
}
// The following method is invoked by the RemoteCertificateValidationDelegate.
// We want to make sure the SSL has no Policy errors and is safe.
public static bool ValidateServerCertificate(
object sender,
X509Certificate certificate,
X509Chain chain,
SslPolicyErrors sslPolicyErrors)
{
if (sslPolicyErrors == SslPolicyErrors.None)
return true;
Console.WriteLine("Certificate error: {0}", sslPolicyErrors);
// Do not allow this client to communicate with unauthenticated servers.
return false;
}
}
public static class Extensions
{
public static byte[] ToByteArray(this string input)
{
UTF8Encoding encoding = new UTF8Encoding();
return encoding.GetBytes(input);
}
public static string ToBase64String(this byte[] input)
{
return Convert.ToBase64String(input);
}
}
}
What is happening when I run this code is the error shown in the following image.
Making an SMS link is very easy in HTML. Here, we will see how to make the SMS link on a webpage. Approach: Using <a> href attribute: Enter the phone number in place of the URL and add sms: before it to make an SMS link. Add the text between the tags that will appear as the clickable link.
TextBelt Open Source. TextBelt Open Source is a REST API that sends outgoing SMS. It uses a free mechanism for sending texts, different from the more reliable paid version available at https://textbelt.com. This project uses carrier-specific gateways to deliver your text messages for free, and without ads.
An SMS only contains text. In an SMS, enter the link address without http:// or https://. For example, www.example.com. SMS does not support HTML.
OK. I worked on it all last night and I made some progress. I used Fiddler to construct the POST message to see any discrepancies between what I had above and what the server expected.
I have got it sending the message and returning a HTTP 200 OK response. Again, this code is not production ready, its just something to test and see if I can get Zeep working. Thank you all who responded and if your looking for ZEEP code, I hope this can help you.
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Net.Security;
using System.Web;
using System.Web.Handlers;
using System.IO;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
namespace ConsoleApplication1
{
class Program
{
public static string API_KEY = "YOUR_API_KEY_GOES_HERE! INCLUDE DASHES!";
public static string SECRET_ACCESS_KEY = "YOUR_SECRET_KEY_GOES_HERE!";
static void Main(string[] args)
{
Console.WriteLine("BLAST - \r\n\r\n");
BlastTcpPost();
Console.WriteLine("SEND - \r\n\r\n");
SendTcpPost();
}
/// <summary>
/// Send a BLAST to all users in your ZEEP account.
/// </summary>
public static void BlastTcpPost()
{
SendSMS(
"https://api.zeepmobile.com/messaging/2008-07-14/blast_message", // URL for Send_Message
"You are on blast", // Message to send
string.Empty // No UserId to send.
);
}
/// <summary>
/// Send a single message to a user in your ZEEP account.
/// </summary>
public static void SendTcpPost()
{
// Note:- 22 I use for the UserId is just a user I have signed up. Yours may be different and you
// might want to pass that in as a parameter.
SendSMS(
"https://api.zeepmobile.com/messaging/2008-07-14/send_message", // URL for Send_Message
"You are a user...good job!", // Message to send
"22" // User Id in your system.
);
}
/// <summary>
/// Uses a TCPClient and SSLStream to perform a POST.
/// </summary>
/// <param name="requestUrl">URL that the POST must be directed to.</param>
/// <param name="body">Message that is to be sent.</param>
/// <param name="user">UserId in your Zeep System. Only required if your sending a Single Message to a User.
/// Otherwise, just send a string.Empty.</param>
/// <returns>Response from the server. (although it will write the response to console)</returns>
public static string SendSMS(string requestUrl, string body, string user)
{
string parameters = "";
string requestHeaders = "";
string responseData = "";
// FORMAT must be Sun, 06 Nov 1994 08:49:37 GMT
string http_date = DateTime.UtcNow.ToString("r");
// Clean the text to send
body = HttpUtility.UrlEncode(body, System.Text.Encoding.UTF8);
if (user.Length > 0) parameters += "user_id=" + user + "&";
if (body.Length > 0) parameters += "body=" + body;
// String that will be converted into a signature.
string canonicalString = API_KEY + http_date + parameters;
//------------START HASH COMPUTATION---------------------
// Compute the Base64 HMACSHA1 value
HMACSHA1 hmacsha1 = new HMACSHA1(SECRET_ACCESS_KEY.ToByteArray());
// Compute the hash of the input file.
byte[] hashValue = hmacsha1.ComputeHash(canonicalString.ToByteArray());
String b64Mac = hashValue.ToBase64String();
String authentication = String.Format("Zeep {0}:{1}", API_KEY, b64Mac);
//-----------END HASH COMPUTATION------------------------
string auth = String.Format("Zeep {0}:{1}", API_KEY, b64Mac);
System.Uri uri = new Uri(requestUrl);
System.Net.Sockets.TcpClient client = new System.Net.Sockets.TcpClient(uri.Host, uri.Port);
string requestMethod = "POST " + uri.LocalPath + " HTTP/1.1\r\n";
// Set Headers for the POST message
requestHeaders += "Host: api.zeepmobile.com\r\n";
requestHeaders += "Authorization: " + auth + "\r\n";
requestHeaders += "Date: " + DateTime.UtcNow.ToString("r") + "\r\n";
requestHeaders += "Content-Type: application/x-www-form-urlencoded\r\n";
requestHeaders += "Content-Length: " + parameters.ToByteArray().Length + "\r\n";
requestHeaders += "\r\n";
// Get the data to be sent as a byte array.
Byte[] data = System.Text.Encoding.UTF8.GetBytes(requestMethod + requestHeaders + parameters + "\r\n");
// Send the message to the connected TcpServer.
NetworkStream stream = client.GetStream();
// SSL Authentication is used because the Server requires https.
System.Net.Security.SslStream sslStream = new System.Net.Security.SslStream(
stream,
false,
new System.Net.Security.RemoteCertificateValidationCallback(ValidateServerCertificate));
sslStream.AuthenticateAsClient(uri.Host);
// Send the data over the SSL stream.
sslStream.Write(data, 0, data.Length);
sslStream.Flush();
// Receive the TcpServer.response.
for (int i = 0; i < 100; i++)
{
if (stream.DataAvailable)
{
break;
}
System.Threading.Thread.Sleep(100);
}
Byte[] bytes = new byte[1024];
System.Text.StringBuilder sb = new System.Text.StringBuilder();
while (stream.DataAvailable)
{
int count = sslStream.Read(bytes, 0, 1024);
if (count == 0)
{
break;
}
sb.Append(System.Text.Encoding.UTF8.GetString(bytes, 0, count));
}
responseData = sb.ToString();
Console.WriteLine(responseData);
// Close everything.
client.Close();
return responseData;
}
// The following method is invoked by the RemoteCertificateValidationDelegate.
// We want to make sure the SSL has no Policy errors and is safe.
public static bool ValidateServerCertificate(
object sender,
X509Certificate certificate,
X509Chain chain,
SslPolicyErrors sslPolicyErrors)
{
// Somehow the cert always has PolicyErrors so I am returning true regardless.
return true;
//if (sslPolicyErrors == SslPolicyErrors.None)
// return true;
//Console.WriteLine("Certificate error: {0}", sslPolicyErrors);
//// Do not allow this client to communicate with unauthenticated servers.
//return false;
}
}
public static class Extensions
{
public static byte[] ToByteArray(this string input)
{
UTF8Encoding encoding = new UTF8Encoding();
return encoding.GetBytes(input);
}
public static string ToBase64String(this byte[] input)
{
return Convert.ToBase64String(input);
}
}
}
Are you sure that you need to manually implement the HTTP protocol in code using a TcpClient
and an SslStream
to communicatie with Zeep? I'd try to just use a HttpWebRequest
object and let the .NET Framework handle the HTTP specific protocol bits for you. Especially since the error message you get back seems to point in the direction of the request you are sending not being able to be understood by the remote server.
(Wasn't there an extra empty line needed between HTTP header and actual content? I never really remember, and I don't have to if I just do the correct .NET Framework WebRequest
...)
Good luck!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With