# 通过google voice发送短信

- URL: https://wuming.si/blog/324/
- Author: Aaron
- Published: 2013-09-25
- Language: en
- Categories: Technology
- Originally published at: https://blog.wo.ai/archives/324

手机上一直装了几个应用，用来给美国手机发送短信，每次都需要登录，比较麻烦。最近也想做一个小应用，其中通过手机发送验证码，觉得google voice最能满足这个要求，反正免费的不用白不用。  
  
在网上找了一些源码，看看如何通过程序来发送短信，基本由三个版本，两个php版，其中一个zend加密版本，被pass掉，另外一个可能接口有些变更，好像发送不太成功。另外还找到一个java版本，测试了一下，可以成功发送，感谢原作者xinghuo.yao的无私奉献。从google code下载的代码，貌似作者是做了一个smsbot，但是我不需要这么复杂的功能，只把googlevoice实现部分摘出来了。

public class GoogleVoice implements Serializable {

/**  
*  
*/  
private static final long serialVersionUID = 5889296580959689523L;  
private String email;  
private String password;

public String getEmail() {  
return email;  
}

public void setEmail(String email) {  
this.email = email;  
}

public String getPassword() {  
return password;  
}

public void setPassword(String password) {  
this.password = password;  
}

private String auth;  
private String rnr;

private long lastSessionTime = 0;

public long getLastSessionTime() {  
return lastSessionTime;  
}

public void setLastSessionTime(long lastSessionTime) {  
this.lastSessionTime = lastSessionTime;  
}

public GoogleVoice(String email, String password)  
throws AuthenticationException {  
this.email = email;  
this.password = password;  
signIn();  
}

private void signIn() throws AuthenticationException {  
retrieveLoginAuth();  
retrieveRnr();  
lastSessionTime = System.currentTimeMillis();  
}

public boolean sendSms(String mobile, String message) {  
if (!checkSession())  
return false;  
try {  
String payload = “id=&phoneNumber=” + mobile + “&text=”  
\+ URLEncoder.encode(message, “UTF-8”) + “&_rnr_se=”  
\+ URLEncoder.encode(rnr, “UTF-8”);  
String data = fetchData(“https://www.google.com/voice/sms/send/”,  
payload, auth);  
// Should return {“ok”:true,”data”:{“code”:0}}  
if (data.contains(“:true”))  
return true;  
else  
return false;  
} catch (Exception e) {  
return false;  
}  
}

private boolean checkSession() {  
if (System.currentTimeMillis() – lastSessionTime >= 1800000l)  
return false;  
lastSessionTime = System.currentTimeMillis();  
return true;  
}

private void retrieveLoginAuth() throws AuthenticationException {  
String payload = “accountType=GOOGLE&Email=” + email + “&Passwd=”  
\+ password + “&service=grandcentral&source=” + “GAE”  
\+ “-GoogleVoiceTool”;  
try {  
String data = fetchData(  
“https://www.google.com/accounts/ClientLogin”, payload,  
null);  
int index = data.indexOf(“Auth=”);  
if (index != -1 && index + 5 < data.length())  
auth = data.substring(data.indexOf(“Auth=”) + 5).trim();  
if (StringUtil.isEmptyOrWhitespace(auth))  
throw new AuthenticationException(“Get Login Auth failed”);  
} catch (Exception e) {  
throw new AuthenticationException(e.getMessage());  
}  
}

private void retrieveRnr() throws AuthenticationException {  
try {  
String data = fetchData(“https://www.google.com/voice/m/”, null,  
auth);  
Pattern p = Pattern.compile(  
“<input.*?name=\”_rnr_se\”.*?value=\”(.*?)\””,  
Pattern.CASE_INSENSITIVE);  
Matcher m = p.matcher(data);

if (m.find())  
rnr = m.group(1);  
if (StringUtil.isEmptyOrWhitespace(rnr))  
throw new AuthenticationException(“Get rnrSEE failed”);  
} catch (Exception e) {  
throw new AuthenticationException(e.getMessage());  
}  
}

private String fetchData(String url, String payload, String auth)  
throws Exception {  
HttpURLConnection con = (HttpURLConnection) new URL(url)  
.openConnection();  
if (auth != null)  
con.setRequestProperty(“Authorization”, “GoogleLogin auth=” + auth);  
con  
.setRequestProperty(  
“User-Agent”,  
“Mozilla/5.0 (iPhone; U; CPU iPhone OS 2_2_1 like Mac OS X; en-us) AppleWebKit/525.18.1 (KHTML, like Gecko) Version/3.1.1 Mobile/5H11 Safari/525.20”);  
con.setRequestProperty(“Content-Type”,  
“application/x-www-form-urlencoded”);  
if (payload == null)  
con.setRequestMethod(“GET”);  
else {  
con.setDoOutput(true);  
con.setRequestMethod(“POST”);  
OutputStream os = con.getOutputStream(); // 输出流，写数据  
os.write(payload.getBytes(“UTF-8”));  
os.flush();  
os.close();  
}  
int code = con.getResponseCode();  
if (code == 200) {  
String response = getContent(con.getInputStream(), code);  
con.disconnect();  
return response;  
} else {  
String response = getContent(con.getErrorStream(), code);  
con.disconnect();  
throw new AuthenticationException(response);  
}  
}

private String getContent(InputStream in, int code) throws Exception {  
BufferedReader reader = new BufferedReader(new InputStreamReader(in,  
“UTF-8”)); // 读取结果  
StringBuffer sb = new StringBuffer(“”);  
String line;  
while ((line = reader.readLine()) != null) {  
sb.append(line).append(“\r\n”);  
if (code != 200 && line.startsWith(“Error=”)) {  
reader.close();  
return line.substring(6);  
}  
}  
reader.close();  
if (code != 200)  
return String.valueOf(code);  
return sb.toString();  
}

public static void main(String[] args) throws AuthenticationException{  
GoogleVoice gv = new GoogleVoice(“用户名”, “密码”);  
if (gv.sendSms(“手机号码”, “hello”))  
System.out.println(“短信已发送至：”);  
else  
System.out.println(“短信未发送”);  
}  
}

早在一两年前，gv貌似还能全世界发短信，后来只限定在美加，不过对于我来说这个已经足够了。再次感谢作者无私奉献，感谢google无私奉献，但愿google别把这个接口给封了。
