整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

Python发送邮件(三十)

单邮件传输协议(SMTP)是一种协议,用于在邮件服务器之间发送电子邮件和路由电子邮件。

Python提供smtplib模块,该模块定义了一个SMTP客户端会话对象,可用于使用SMTP或ESMTP侦听器守护程序向任何互联网机器发送邮件。

这是一个简单的语法,用来创建一个SMTP对象,稍后将演示如何用它来发送电子邮件 -

import smtplib
smtpObj = smtplib.SMTP( [host [, port [, local_hostname]]] )

这里是上面语法的参数细节 -

  • host - 这是运行SMTP服务器的主机。可以指定主机的IP地址或类似felix.com的域名。这是一个可选参数。
  • port - 如果提供主机参数,则需要指定SMTP服务器正在侦听的端口。通常这个端口默认值是:25。
  • local_hostname - 如果SMTP服务器在本地计算机上运行,那么可以只指定localhost选项。

SMTP对象有一个sendmail的实例方法,该方法通常用于执行邮件发送的工作。它需要三个参数 -

  • sender - 具有发件人地址的字符串。
  • receivers - 字符串列表,每个收件人一个。
  • message - 作为格式如在各种RFC中指定的字符串。

1.使用Python发送纯文本电子邮件

示例

以下是使用Python脚本发送一封电子邮件的简单方法 -

#!/usr/bin/python3
import smtplib
sender = 'from@fromdomain.com'
receivers = ['to@todomain.com']
message = """From: From Person <from@fromdomain.com>
To: To Person <to@todomain.com>
Subject: SMTP e-mail test
This is a test e-mail message.
"""
try:
 smtpObj = smtplib.SMTP('localhost')
 smtpObj.sendmail(sender, receivers, message) 
 print "Successfully sent email"
except SMTPException:
 print "Error: unable to send email"

在这里,已经发送了一封基本的电子邮件,使用三重引号,请注意正确格式化标题。一封电子邮件需要一个From,To和一个Subject标题,与电子邮件的正文与空白行分开。

要发送邮件,使用smtpObj连接到本地机器上的SMTP服务器。 然后使用sendmail方法以及消息,从地址和目标地址作为参数(即使来自和地址在电子邮件本身内,这些并不总是用于路由邮件)。

如果没有在本地计算机上运行SMTP服务器,则可以使用smtplib客户端与远程SMTP服务器进行通信。除非您使用网络邮件服务(如gmail或Yahoo! Mail),否则您的电子邮件提供商必须向您提供可以提供的邮件服务器详细信息。以腾讯QQ邮箱为例,具体如下:

mail = smtplib.SMTP('smtp.qq.com', 587) # 端口465或587

2.使用Python发送HTML电子邮件

当使用Python发送邮件信息时,所有内容都被视为简单文本。 即使在短信中包含HTML标签,它也将显示为简单的文本,HTML标签将不会根据HTML语法进行格式化。 但是,Python提供了将HTML消息作为HTML消息发送的选项。

发送电子邮件时,可以指定一个Mime版本,内容类型和发送HTML电子邮件的字符集。

以下是将HTML内容作为电子邮件发送的示例 -

#!/usr/bin/python3
import smtplib
message = """From: From Person <from@fromdomain.com>
To: To Person <to@todomain.com>
MIME-Version: 1.0
Content-type: text/html
Subject: SMTP HTML e-mail test
This is an e-mail message to be sent in HTML format
<b>This is HTML message.</b>
<h1>This is headline.</h1>
"""
try:
 smtpObj = smtplib.SMTP('localhost')
 smtpObj.sendmail(sender, receivers, message) 
 print "Successfully sent email"
except SMTPException:
 print "Error: unable to send email"

3.发送附件作为电子邮件

要发送具有混合内容的电子邮件,需要将Content-type标题设置为multipart / mixed。 然后,可以在边界内指定文本和附件部分。

一个边界以两个连字符开始,后跟一个唯一的编号,不能出现在电子邮件的消息部分。 表示电子邮件最终部分的最后一个边界也必须以两个连字符结尾。

所附的文件应该用包(“m”)功能编码,以便在传输之前具有基本的64编码。

4.发送示例

首先我们要知道用python代理登录qq邮箱发邮件,是需要更改自己qq邮箱设置的。在这里大家需要做两件事情:邮箱开启SMTP功能 、获得授权码。之后我们来看看如何更改模板代码,实现使用Python登录QQ邮箱发送QQ邮件。

注意:也可以使用其他服务商的 SMTP 访问(QQ、网易、Gmail等)。

使用QQ邮件发送邮件之前如何设置授权码,参考:

http://service.mail.qq.com/cgi-bin/help?subtype=1&&id=28&&no=1001256

4.1.发送一纯文本邮件到指定邮件

#! /usr/bin/env python
#coding=utf-8
from email.mime.text import MIMEText
from email.header import Header
from smtplib import SMTP_SSL
#qq邮箱smtp服务器
host_server = 'smtp.qq.com'
#sender_qq为发件人的qq号码
sender_qq = '123123123@qq.com'
#pwd为qq邮箱的授权码
pwd = '****kenbb***' ## xh**********bdc
#发件人的邮箱
sender_qq_mail = '123123123@qq.com'
#收件人邮箱
receiver = 'felix.com@gmail.com'
#邮件的正文内容
mail_content = '你好,这是使用python登录qq邮箱发邮件的测试'
#邮件标题
mail_title = 'Maxsu的邮件'
#ssl登录
smtp = SMTP_SSL(host_server)
#set_debuglevel()是用来调试的。参数值为1表示开启调试模式,参数值为0关闭调试模式
smtp.set_debuglevel(1)
smtp.ehlo(host_server)
smtp.login(sender_qq, pwd)
msg = MIMEText(mail_content, "plain", 'utf-8')
msg["Subject"] = Header(mail_title, 'utf-8')
msg["From"] = sender_qq_mail
msg["To"] = receiver
smtp.sendmail(sender_qq_mail, receiver, msg.as_string())
smtp.quit()

执行上面代码后,登录接收邮件的邮件帐号,这里接收邮件的账号为:felix.com@gmail.com,登录 http://gmail.com 应该会看到有接收到邮件如下 -

录内容

目录内容 2

0. 修改记录 3

1. 短信概念 4

2. 短信分类 5

2.1. TEXT短信 5

2.2. PDU短信 5

3. 短信应用 6

3.1. 发送短信 6

3.1.1. TEXT短信方式 6

3.1.2. PDU短信方式 6

3.2. 编写短信 7

3.2.1. TEXT短信方式 7

3.2.2. PDU短信方式 7

3.3. 转发短信 8

3.4. 读取短信 9

3.4.1. TEXT短信方式 9

3.4.2. PDU短信方式 9

3.5. 删除短信 10

3.5.1. TEXT短信方式 10

3.5.2. PDU短信方式 11

4. PDU串分类及结构 12

4.1. SUBMIT-PDU 12

4.1.1. 结构 12

4.1.2. 说明 12

4.1.3. 举例分析 15

4.2. DELIVER-PDU 16

4.2.1. 结构 17

4.2.2. 说明 17

4.2.3. 举例分析 19

5. 短信工作过程 22

5.1. 设备之间的交互过程 22

5.2. 平台的消息处理过程 23

5.2.1. 发送短信 23

5.2.2. 接收短信 23

0. 修改记录

版本

日期

作者

修改内容记录

1.0

2012-08-10

Vicent.Gao

初始版本,讲述了短信的基本操作,及PDU串的结构

2.0

2012-08-17

Vicent.Gao

加入新的一章:第5章 “短信工作过程”

1. 短信概念

短消息,即SMS,英文全称short message service,是一种使用手机发送和接收有限长度文本信息的通讯服务;

更加详细的介绍,请查看链接:

http://www.jl.10086.cn/whatsnew/newrelease/duanxin.html

2. 短信分类

在用户使用的角度看,短信共分为2类,分别是TEXT短信、PDU短信。

在写短信、发送短信时,可以选择使用TEXT短信方式,也可以选择使用PDU短信方式;

在读取短信时,可以选择使用TEXT短信方式,也可以使用PDU短信方式;

编写的短信、接收的短信,实际是以PDU短信方式存储在ME或SM中;

在发送短信时,实际是以PDU短信方式发往SCA,再由SCA转发至对方手机;

2.1 TEXT短信

以可读的方式,编写、发送、读取短信。在编写短信、发送短信时,需要内部转换成PDU模式,才能进行存储、发送。

如:

AT+CMGR=1

+CMGR: "REC UNREAD","+8615055135325","","2012/08/10 10:56:08+32"

0123456789

OK

2.2 PDU短信

根据指定的PDU格式,填充必要的域,如<SCA>, <FO>,<DCS>等,不需要内部进行转换,可以直接进行存储或发送。也可以使用PDU短信方式,读取编写和接收的短信。

如:

AT+CMGR=1

+CMGR: 1,,29

0891683108501505F0040D91685150155323F50000218001016580230AB0986C46ABD96EB81C

OK

3. 短信应用

客户在使用短信功能时,可以完成发送短信、编写短信、转发短信、读取短信、删除短信的操作。

3.1 发送短信

3.1.1 TEXT短信方式

AT+CMGF=1 //设置使用TEXT短信方式

OK

AT+CSCS="GSM" //设置编辑短信时,使用的字符集

OK

AT+CMGS="15055135325" //使用CMGS发送短信给自身,此处需要填写DA,即目标地址

> 0123456789 //按<CTRL+Z>开始发送短信

+CMGS: 28 //短信已发送,MR=28,其中MR为Messge Reference,用来唯一标识一条短信

OK //短信发送成功

+CMTI: "SM",1 //接收到的短信,存储在SM中,索引号为1的位置上

参考的QCOM Script,请见压缩包路径:

QCOM_Script\CMGS\CMGS_TEXT.ini

3.1.2 PDU短信方式

AT+CMGF=0 //设置使用PDU短信方式

OK

AT+CMGS=24 //使用CMGS发送短信给自身,此处需要填写TPDU串的长度,即PDU串中除去SCA域之后的数据长度,以Byte为单位

> 0891683108501505F011000D91685150155323F500000A0AB0986C46ABD96EB81C //按<CTRL+Z>开始发送短信

+CMGS: 29 //短信已发送,MR=29,其中MR为Messge Reference,用来唯一标识一条短信

OK //短信发送成功

+CMTI: "SM",2 //接收到的短信,存储在SM中,索引号为2的位置上

参考的QCOM Script,请见压缩包路径:

QCOM_Script\CMGS\CMGS_PDU.ini

3.2 编写短信

3.2.1 TEXT短信方式

AT+CMGF=1 //设置使用TEXT短信方式

OK

AT+CSCS="GSM" //设置编辑短信时,使用的字符集

OK

AT+CMGW //使用CMGW编写短信,没有指明DA,即目标地址,也可以在命令中指明

> 0123456789 //按<CTRL+Z>开始存储短信

+CMGW: 5 //编写的短信,存储在索引号为5的位置上

OK //编写短信成功

参考的QCOM Script,请见压缩包路径:

QCOM_Script\CMGW\CMGW_TEXT.ini

3.2.2 PDU短信方式

AT+CMGF=0 //设置使用PDU短信方式

OK

AT+CMGW=17 //使用CMGW编写短信,此处需要填写TPDU串的长度,即PDU串中除去SCA域之后的数据长度,以Byte为单位

> 0011FF00000000470AB0986C46ABD96EB81C //按<CTRL+Z>开始存储短信

+CMGW: 7 //编写的短信,存储在索引号为7的位置上

OK //编写短信成功

参考的QCOM Script,请见压缩包路径:

QCOM_Script\CMGW\CMGW_PDU.ini

3.3 转发短信

需要指明短信存储时使用的索引号,才能完成转发操作。由于短信在存储时,都是以PDU短信方式来进行存储的,所以此命令与使用的短信方式(TEXT或PDU)无关。

AT+CMGF=0 //设置使用TEXT短信方式

OK

AT+CSCS="GSM" //设置编辑短信时,使用的字符集

OK

AT+CMSS=7,"15055135325" //使用CMSS转发短信给自身,此短信存储在索引号为7的位置上,此处指明了DA,即目标地址

+CMSS: 30 //短信已发送,MR=29,其中MR为Messge Reference,用来唯一标识一条短信

OK //短信发送成功

+CMTI: "SM",9 //接收到的短信,存储在SM中,索引号为9的位置上

AT+CMGF=1 //设置使用PDU短信方式

OK

AT+CSCS="GSM" //设置编辑短信时,使用的字符集

OK

AT+CMSS=7,"15055135325" //使用CMSS转发短信给自身,此短信存储在索引号为7的位置上,此处指明了DA,即目标地址

+CMSS: 31 //短信已发送,MR=29,其中MR为Messge Reference,用来唯一标识一条短信

OK //短信发送成功

+CMTI: "SM",10 //接收到的短信,存储在SM中,索引号为10的位置上

注:

在TEXT短信方式、PDU短信方式下,转发同一条短信,都可以成功发送,则说明CMSS转发短信与具体采用的短信方式(使用CMGF命令设置)无关。

参考的QCOM Script,请见压缩包路径:

QCOM_Script\CMSS\CMSS.ini

3.4 读取短信

使用CMGD读取单条短信,使用CMGL读取某一类别的短信。

3.4.1 TEXT短信方式

AT+CMGF=1 //设置使用TEXT短信方式

OK

AT+CMGR=1 //使用CMGR命令,读取索引号1位置上的短信

+CMGR: "REC UNREAD","+8615055135325","","2012/08/10 10:56:08+32"

0123456789 //在TEXT短信方式下,列出的短信内容

OK

AT+CMGL=? //使用CMGL读取指定类别的短信,在TEXT短信方式下,查询CMGL命令的用法

+CMGL: ("REC UNREAD","REC READ","STO UNSENT","STO SENT","ALL") //在TEXT短信方式下,使用String方式来指明要读取短信的类别

OK

AT+CMGL="STO UNSENT" //显示所有未发送的短信

+CMGL: 3,"STO UNSENT","","", //第1条未发送短信,存储在索引号3位置上

0123456789

+CMGL: 4,"STO UNSENT","15055135325","", //第2条未发送短信,存储在索引号4位置上

0123456789

+CMGL: 5,"STO UNSENT","","", //第3条未发送短信,存储在索引号5位置上

0123456789

+CMGL: 6,"STO UNSENT","","", //第4条未发送短信,存储在索引号6位置上

0123456789

OK

参考的QCOM Script,请见压缩包路径:

QCOM_Script\CMGR+CMGL\CMGR+CMGL_TEXT.ini

3.4.2 PDU短信方式

AT+CMGF=0 //设置使用PDU短信方式

OK

AT+CMGR=1 //使用CMGR命令,读取索引号1位置上的短信

+CMGR: 1,,29

0891683108501505F0040D91685150155323F50000218001016580230AB0986C46ABD96EB81C //在PDU短信方式下,列出的短信内容

OK

AT+CMGL=? //使用CMGL读取指定类别的短信,在PDU短信方式下,查询CMGL命令的用法

+CMGL: (0-4) //在PDU短信方式下,使用Integer方式来指明要读取短信的类别

OK

AT+CMGL=2 //显示所有未发送的短信

+CMGL: 3,2,,17 //第1条未发送短信,存储在索引号3位置上

0011FF00000000470AB0986C46ABD96EB81C

+CMGL: 4,2,,23 //第2条未发送短信,存储在索引号4位置上

0011FF0B815150155323F50000470AB0986C46ABD96EB81C

+CMGL: 5,2,,17 //第3条未发送短信,存储在索引号5位置上

0011FF00000000470AB0986C46ABD96EB81C

+CMGL: 6,2,,17 //第4条未发送短信,存储在索引号6位置上

0011FF00000000470AB0986C46ABD96EB81C

OK

参考的QCOM Script,请见压缩包路径:

QCOM_Script\CMGR+CMGL\CMGR+CMGL_PDU.ini

3.5 删除短信

在删除短信时,建议使用CMGD删除单条命令,使用QMGDA删除指定类别的短信。当然,使用CMGD命令的<delflag>参数,也可以删除指定类别的短信。

3.5.1 TEXT短信方式

AT+CMGF=1 //设置使用TEXT短信方式

OK

AT+CMGD=1 //使用CMGD删除索引号1位置上的短信

OK

AT+QMGDA=? //使用QMGDA删除某一类别的短信,在TEXT短信方式下,查询QMGDA命令的用法

+QMGDA:("DEL READ","DEL UNREAD","DEL SENT","DEL UNSENT","DEL INBOX","DEL ALL") //在TEXT短信方式下,使用String方式来指明要删除短信的类别

OK

AT+QMGDA="DEL READ" //删除所有已读短信

OK

参考的QCOM Script,请见压缩包路径:

QCOM_Script\CMGD+QMGDA\CMGD+QMGDA_TEXT.ini

3.5.2 PDU短信方式

AT+CMGF=0 //设置使用PDU短信方式

OK

AT+CMGD=1 //使用CMGD删除索引号1位置上的短信

OK

AT+QMGDA=? //使用QMGDA删除某一类别的短信,在PDU短信方式下,查询QMGDA命令的用法

+QMGDA:(1-6) //在PDU短信方式下,使用Integer方式来指明要删除短信的类别

OK

AT+QMGDA=1 //删除所有已读短信

OK

参考的QCOM Script,请见压缩包路径:

QCOM_Script\CMGD+QMGDA\CMGD+QMGDA_PDU.ini

4. PDU串分类及结构

在使用PDU短信方式,进行短信的发送、编写、读取时,对于PDU串结构的了解是很有必要的。

PDU串共有2类,分别是SUBMIT-PDU,DELIVER-PDU,各有不同的结构。

4.1 SUBMIT-PDU

SUBMIT-PDU,是发送短信时采用的PDU串。

SUBMIT-PDU

SCA

TPDU




DA






Len

Type

Addr

FO

MR

Len

Type

Addr

PID

DCS

VP

UDL

UD

P1

P2

P3

P4

P5

P6

P7

P8

P9

P10

P11

P12

P13

1

0~1

0~10

1

1

1

1

0~10

1

1

1

1

0~140

1 ~ 12



2~12






4.1.1 结构

注:

表中的第1行为 表头部分,说明表所要表达的内容;

表中的第2行为 PDU串结构中,包含有2大部分;

表中的第3行为 PDU串结构中,TPDU部分中再划分的结构;

表中的第4行为 PDU串结构中,细分的每个部分;

表中的第5行为 对PDU串结构中,细分的每个部分,进行重新编码,方便后续的描述;

表中的第6行为 PDU串结构中,细分的每个部分,编码时占用的字节数范围;

表中的第7行为 PDU串结构中,包含的地址区域,编码时占用的字节数范围;

4.1.2 说明

  • P1

P1区域属于SCA域的一部分,固定占有1个字节,表示SCA域的长度,实际上表示的是P2区域和P3区域共同占有的字节数。

当P1=0x00时,表示SCA域不存在,此时平台会从CSCA命令中,读取需要的短信服务中心号码。

  • P2

P2区域属于SCA域的一部分,当P1=0x00时,P2区域将不存在;当P1!=0x00时,P2 区域存在,并固定占有1字节大小;

P2区域,用于表示短信服务中心号码的类型,可能取得值有:0x91(国际型),0x81(未知类型),0xA1(国内型)。

  • P3

P3区域属于SCA域的一部分,当P1=0x00时,P3区域将不存在;当P1!=0x00时,P3 区域存在,其占有的字节数为:P1 – 1。

P3区域,用于存储短信服务中心的号码,此号码采用BCD编码

  • P4

P4区域固定占有1个字节,为TPDU域的第1个字节,即First Octet。P4区域用于设置PDU串的类型,及其他重要参数。

其结构如下表:

SUBMIT-PDU FO (First Octet)

7

6

5

4

3

2

1

0

RP

UDHI

SRR

VPF

VPF

RD

MTI

MTI

说明如下:

  • MTI 2bit消息类型00收01发
  • RD 1bit重复信元丢弃0通知服务中心碰到同源同目的地同样的MR短消息序号的短消息接受1抛弃此时将在短消息提交报告中返回一个适当的FCS值
  • VPF 2bit有效期限格式00 VP不存在10 VP区存在用一个字节表示是相对值01 保留11 存在半个字节表示绝对值
  • SRR 1bit状态报告要求.
  • UDHI 1bit用户数据头标示0用户数据没有头信息1有一般为0
  • RP 1bit是否有回复路径的标示1有0没有一般为0

[Vicent.Gao]:后续会对此段内容,针对平台中的代码,进行更加详细的描述。

  • P5

P5区域固定占有1个字节,为Message Reference,用于唯一标识一条短信。

  • P6

P6区域属于DA域的一部分,固定占有1个字节,表示DA域的长度,实际上表示的是P8区域含有的BCD码字符的个数

  • P7

P7区域属于DA域的一部分,固定占有1个字节,表示目标地址的类型,可能取得值有:0x91(国际型),0x81(未知类型),0xA1(国内型)。

  • P8

P8区域属于DA域的一部分,当P6=0x00时,P8区域将不存在;当P6!=0x00时,P8区域存在,其占有的字节数为:P6 / 2。P8区域用于存储目的地址号码。

  • P9

P9区域固定占有1个字节,为Protocol Identifier,用于标识一条短信的种类,为文本短信,还是为其他的短信,如Voice Telephone, E-Mail SMS,一般设置为0x00即可。

  • P10

P10区域固定占有1个字节,为Data Coding Scheme,表示短信内容采用的编码,及短信的类别(Message Class)。

其结构如下表:

DCS (Data Coding Scheme)

7

6

5

4

3

2

1

0

-

-

Bit5

Bit4

Bit3

Bit2

Bit1

Bit0

说明如下:

  • Bit7 Bit6

一般设置为00

  • Bit5

文本是否压缩,0表示未压缩,1表示采用GSM标准压缩。

  • Bit4

是否指定短消息类别,0表示没有指定,1表示已指定。

  • Bit3 Bit2

指定短信内容采用的编码,00表示默认字母表,01表示8bit数据,10表示UCS编码,11表示保留。

  • Bit1 Bit0

指定短消息类别,00表示Class 0,01表示Class 1,10表示Class 2,11表示Class 3。

其中:

Class 0,直接显示到用户终端;

Class 1,短消息存储在SIM卡上;

Class 2,短消息必须存储在SIM卡上禁止直接传输到终端;

Class 3,短消息存贮在用户设备上;

平台解码方法:

smsal_decode_dcs

  • P11

P11区域,固定占有1个字节,即Validiy Period,用于表示短信服务中心在收到短信后,最长可以暂存的时间,过了有效时间之后,如果这条短信仍然没有被短信服务中心转发出去,那么将会被短信服务中心丢弃。

有效时间,分为2种格式,相对格式和绝对格式,一般都采用相对格式。

相对格式的有效时间计算方法如表:

VP

计算方法

00 – 8F

(VP+1)*5 分钟 从 5 分钟间隔到 12 个小时

90 – A7

12 小时 + (VP – 143)*30 分钟

A8 – C4

(VP – 166) * 1 天

C5 – FF

(VP – 192) * 1 周

  • P12

P12区域,固定占有1个字节,即User Data Length,表示用户数据长度。

当短信内容采用GSM-7bit编码时,其表示P13区域含有的有效字符的个数;

当短信内容采用其他编码时,如UCS2,其表示P13区域含有的字节数;

  • P13

当P12=0x00时,P13区域不存在;当P12!=0x00时,P13区域存在,用于存储用户实际发送的短信内容。

P13区域最大只有140字节的空间可供利用,当短信内容采用GSM-7bit编码时,其最大可以存储140 + 140 / 7 = 160个字符;当短信内容采用UCS2编码时,其最大可以存储140 / 2 = 70个字符,如汉字字符。

4.1.3 举例分析

SUBMIT-PDU串如下:

0891683108501505F011000D91685150155323F500000A0AB0986C46ABD96EB81C

拆分如下:

08 91 683108501505F0 11 00 0D 91 685150155323F5 00 00 0A 0A B0986C46ABD96EB81C

08 91 683108501505F0 11 00 0D 91 685150155323F5 00 00 AA 0A B0986C46ABD96EB81C

如表:

P1/SCA Len

P2/SCA Type

P3/SCA Addr

P4/FO

P5/MR

08

91

683108501505F0

11

00

P6/DA Len

P7/DA Type

P8/DA Addr

P9/PID

P10/DCS

0D

91

685150155323F5

00

00

P11/VP

P12/UDL

P13/UD



0A

0A

B0986C46ABD96EB81C



分析结果:

  • P1

内容:08

解析:SCA域长度为8个字节,即P2区域和P3区域总共的区域有8个字节,其中P2区域固定占用1个字节,P3区域占用7个字节。

  • P2

内容:91

解析:短信服务中心号码为国际型。

  • P3

内容:683108501505F0

解析:短信服务中心号码为:8613800551500

  • P4

内容:11

解析:此PDU类型为SUBMIT-PDU,采用相对有效期格式。

  • P5

内容:00

解析:Messge Reference,即短消息发送参考号,采用默认值00。

  • P6

内容:0D

解析:DA域长度为0D/02=7个字节,含有0D=14个BCD码字符,即P8区域占有7个字节,含有14个BCD码字符。

  • P7

内容:91

解析:目的地址号码类型为国际型。

  • P8

内容:685150155323F5

解析:目的地址号码为:8615055135325

  • P9

内容:00

解析:Protocol Identifier,采用默认值00,即普通文本短消息。

  • P10

内容:00

解析:Data Coding Scheme,采用默认值00,即GSM-7bit编码,Class 1类型。

  • P11

内容:0A

解析:短消息在短信服务中心存储的有效时间为:(0A + 1) * 5 = 55分钟。

  • P12

内容:0A

解析:由于采用GSM-7bit编码,所以此处表示P13区域内含有10个字符

  • P13

内容:B0986C46ABD96EB81C

解析:通过对GSM-7bit编码内容进行解码,得知短信内容为:0123456789

4.2 DELIVER-PDU

DELIVER-PDU,是接收到的短信采用的PDU串。

4.2.1 结构

DELIVER-PDU

SCA

TPDU



OA






Len

Type

Addr

FO

Len

Type

Addr

PID

DCS

SCST

UDL

UD

P1

P2

P3

P4

P5

P6

P7

P8

P9

P10

P11

P12

1

1

6~10

1

1

1

6~10

1

1

7

1

0~140

8~ 12


8~12






注:

表中的第1行为 表头部分,说明表所要表达的内容;

表中的第2行为 PDU串结构中,包含有2大部分;

表中的第3行为 PDU串结构中,TPDU部分中再划分的结构;

表中的第4行为 PDU串结构中,细分的每个部分;

表中的第5行为 对PDU串结构中,细分的每个部分,进行重新编码,方便后续的描述;

表中的第6行为 PDU串结构中,细分的每个部分,编码时占用的字节数范围;

表中的第7行为 PDU串结构中,包含的地址区域,编码时占用的字节数范围;

4.2.2 说明

  • P1

P1区域属于SCA域的一部分,固定占有1个字节,表示SCA域的长度,实际上表示的是P2区域和P3区域共同占有的字节数。

  • P2

P2区域属于SCA域的一部分,固定占有1个字节,用于表示短信服务中心号码的类型,可能取得值有:0x91(国际型),0x81(未知类型),0xA1(国内型)。

  • P3

P3区域属于SCA域的一部分,其占有的字节数为:P1 – 1,用于存储短信服务中心的号码,此号码采用BCD编码

  • P4

P4区域固定占有1个字节,为TPDU域的第1个字节,即First Octet。P4区域用于设置PDU串的类型,及其他重要参数。

其结构如下表:

DELIVER-PDU FO (First Octet)

7

6

5

4

3

2

1

0

RP

UDHI

SRI

-

-

MMS

MTI

MTI

说明如下:

  • MTI 2bit消息类型00收01发
  • MMS 1bit短消息服务中心是否有更多短消息等待移动台1有0无默认为1
  • SRI 1bit状态报告标示0不需要状态返回到移动设备1需要默认为0
  • UDHI 1bit用户数据头标示0用户数据没有头信息1有一般为0
  • RP 1bit是否有回复路径的标示1有0没有一般为0

[Vicent.Gao]:后续会对此段内容,针对平台中的代码,进行更加详细的描述。

  • P5

P5区域属于OA域的一部分,固定占有1个字节,表示DA域的长度,实际上表示的是P7区域含有的BCD码字符的个数。

  • P6

P6区域属于DA域的一部分,固定占有1个字节,表示目标地址的类型,可能取得值有:0x91(国际型),0x81(未知类型),0xA1(国内型)。

  • P7

P7区域属于DA域的一部分,其占有的字节数为:P5 / 2,用于存储发送方的号码。

  • P8

P8区域固定占有1个字节,为Protocol Identifier,用于标识一条短信的种类,为文本短信,还是为其他的短信,如Voice Telephone, E-Mail SMS,一般都为0x00,即普通文本短信。

  • P9

P9区域固定占有1个字节,为Data Coding Scheme,表示短信内容采用的编码,及短信的类别(Message Class)。

其结构如下表

DCS (Data Coding Scheme)

7

6

5

4

3

2

1

0

-

-

Bit5

Bit4

Bit3

Bit2

Bit1

Bit0

说明如下:

  • Bit7 Bit6

一般设置为00

  • Bit5

文本是否压缩,0表示未压缩,1表示采用GSM标准压缩。

  • Bit4

是否指定短消息类别,0表示没有指定,1表示已指定。

  • Bit3 Bit2

指定短信内容采用的编码,00表示默认字母表,01表示8bit数据,10表示UCS编码,11表示保留。

  • Bit1 Bit0

指定短消息类别,00表示Class 0,01表示Class 1,10表示Class 2,11表示Class 3。

其中:

Class 0,直接显示到用户终端;

Class 1,短消息存储在SIM卡上;

Class 2,短消息必须存储在SIM卡上禁止直接传输到终端;

Class 3,短消息存贮在用户设备上;

平台解码方法:

smsal_decode_dcs

  • P10

P10区域固定占有7个字节,即Serive Center Time Stamp,用于存储SCA转发该条短信的时间戳。

其结构如下表:

SCTS

1

2

3

4

5

6

7

时区

说明如下:

假设P10区域为:21800101658023,再拆分成:21 80 01 01 65 80 23,则表示SCTS为:12年 08月 10日 10时 56分 08秒 32时区

  • P11

P11区域,固定占有1个字节,即User Data Length,表示用户数据长度。

当短信内容采用GSM-7bit编码时,其表示P12区域含有的有效字符的个数;

当短信内容采用其他编码时,如UCS2,其表示P12区域含有的字节数;

  • P12

当P11=0x00时,P12区域不存在;当P11!=0x00时,P12区域存在,用于存储用户实际发送的短信内容。

P12区域最大只有140字节的空间可供利用,当短信内容采用GSM-7bit编码时,其最大可以存储140 + 140 / 7 = 160个字符;当短信内容采用UCS2编码时,其最大可以存储140 / 2 = 70个字符,如汉字字符。

4.2.3 举例分析

DELIVER-PDU串如下:

0891683108501505F0040D91685150155323F50000218001016580230AB0986C46ABD96EB81C

拆分如下:

08 91 683108501505F0 04 0D 91 685150155323F5 00 00 21800101658023 0A B0986C46ABD96EB81C

如表:

P1/SCA Len

P2/SCA Type

P3/SCA Addr

P4/FO

P5/OA Len

08

91

683108501505F0

04

0D

P6/OA Type

P7/OA Addr

P8/PID

P9/DCS

P10/SCTS

91

685150155323F5

00

00

21800101658023

P11/UDL

P12/UD




0A

B0986C46ABD96EB81C




分析结果:

  • P1

内容:08

解析:SCA域长度为8个字节,即P2区域和P3区域总共的区域有8个字节,其中P2区域固定占用1个字节,P3区域占用7个字节。

  • P2

内容:91

解析:短信服务中心号码为国际型。

  • P3

内容:683108501505F0

解析:短信服务中心号码为:8613800551500

  • P4

内容:04

解析:此PDU类型为DELIVER-PDU。

  • P5

内容:0D

解析:OA域长度为0D/02=7个字节,含有0D=14个BCD码字符,即P7区域占有7个字节,含有14个BCD码字符。

  • P6

内容:91

解析:发送方号码类型为国际型。

  • P7

内容:685150155323F5

解析:发送方号码为:8615055135325

  • P8

内容:00

解析:Protocol Identifier,采用默认值00,即普通文本短消息。

  • P9

内容:00

解析:Data Coding Scheme,采用默认值00,即GSM-7bit编码,Class 1类型。

  • P10

内容:21800101658023

解析:短消息服务中心在转发此条短信的时间戳为:2012年08月10日10时56分08秒。

  • P11

内容:0A

解析:由于采用GSM-7bit编码,所以此处表示P12区域内含有10个字符。

  • P12

内容:B0986C46ABD96EB81C

解析:通过对GSM-7bit编码内容进行解码,得知短信内容为:0123456789

5. 短信工作过程

5.1 设备之间的交互过程

5.2 平台的消息处理过程

5.2.1 发送短信

5.2.2 接收短信

码示例

#python3
#接口类型:互亿无线触发短信接口,支持发送验证码短信、订单通知短信等。
#账户注册:请通过该地址开通账户 http://user.ihuyi.com/?9vXc7
 
#注意事项:
#(1)调试期间,请用默认的模板进行测试,默认模板详见接口文档;
#(2)请使用 用户名 及 APIkey来调用接口,APIkey在会员中心可以获取;
#(3)该代码仅供接入互亿无线短信接口参考使用,客户可根据实际需要自行编写;

import urllib.parse
import urllib.request

#接口地址
url = 'http://106.ihuyi.com/webservice/sms.php?method=Submit'

#定义请求的数据
values = {
    'account':'xxxxxxxx',
    'password':'xxxxxxxxxxxx',
    'mobile':'134xxxxxxxx',
    'content':'您的验证码是:7835。请不要把验证码泄露给其他人。',
    'format':'json',
}

#将数据进行编码
data = urllib.parse.urlencode(values).encode(encoding='UTF8')

#发起请求
req = urllib.request.Request(url, data)
response = urllib.request.urlopen(req)
res = response.read()

#打印结果
print(res.decode("utf8"))

-----------------------------------
#python2

#接口类型:互亿无线触发短信接口,支持发送验证码短信、订单通知短信等。
#账户注册:请通过该地址开通账户http://user.ihuyi.com/register.html
#注意事项:
#(1)调试期间,请使用用系统默认的短信内容:您的验证码是:【变量】。请不要把验证码泄露给其他人。
#(2)请使用 APIID 及 APIKEY来调用接口,可在会员中心获取;
#(3)该代码仅供接入互亿无线短信接口参考使用,客户可根据实际需要自行编写;
   
#!/usr/local/bin/python
#-*- coding:utf-8 -*-
import httplib
import urllib
 
host  = "106.ihuyi.com"
sms_send_uri = "/webservice/sms.php?method=Submit"
 
#查看用户名 登录用户中心->验证码通知短信>产品总览->API接口信息->APIID
account  = "用户名"
#查看密码 登录用户中心->验证码通知短信>产品总览->API接口信息->APIKEY
password = "密码"
 
def send_sms(text, mobile):
    params = urllib.urlencode({'account': account, 'password' : password, 'content': text, 'mobile':mobile,'format':'json' })
    headers = {"Content-type": "application/x-www-form-urlencoded", "Accept": "text/plain"}
    conn = httplib.HTTPConnection(host, port=80, timeout=30)
    conn.request("POST", sms_send_uri, params, headers)
    response = conn.getresponse()
    response_str = response.read()
    conn.close()
    return response_str
 
if __name__ == '__main__':
 
    mobile = "138xxxxxxxx"
    text = "您的验证码是:121254。请不要把验证码泄露给其他人。"
 
    print(send_sms(text, mobile))



你学会了吗?