微信 网站应用开发,天津网站建设方案托管,2023年电商数据报告,晋城网站建设开发1. SMTP邮件发送客户端
在本系列的第4篇文章《鸿蒙网络编程系列4-实现SMTP邮件发送客户端》中#xff0c;基于ArkTS语言在API9环境下使用TCPSocket对象演示了SMTP客户端的实现#xff0c;并且通过腾讯邮件服务器执行了实际的邮件发送。不过#xff0c;在2024年末#xff0…1. SMTP邮件发送客户端
在本系列的第4篇文章《鸿蒙网络编程系列4-实现SMTP邮件发送客户端》中基于ArkTS语言在API9环境下使用TCPSocket对象演示了SMTP客户端的实现并且通过腾讯邮件服务器执行了实际的邮件发送。不过在2024年末腾讯发了一个通知从2024年11月20日开始停用以明文非加密方式登录的第三方邮件客户端必需启用SSL/TLS加密方式。不过除了腾讯邮件发送服务器还有很多其他邮件服务器支持使用明文登录其中比较知名的有搜狐邮箱可以通过如下的方式启用 保存的时候搜狐邮箱会自动生成独立密码将来可以使用这个密码执行登录。
本文将使用仓颉语言在API17环境下实现SMTP邮件发送客户端具体的邮件发送将通过搜狐邮箱实现关于SMTP协议的相关基础知识可以参考本系列第4篇文章的第一部分这里不再赘述。
2. 邮件发送客户端示例演示
本示例运行后的页面如图所示 输入SMTP服务器地址和端口这里输入的是搜狐邮箱发送服务器的地址再输入邮箱用户名和登录密码此时就可以单击“登录”按钮执行登录了如图所示 登录成功后输入收件人、发件人邮箱地址以及邮件的标题和内容再单击下面的“发送邮件”按钮既可以执行邮件发送过程如下所示 发送成功后登录收件人的邮箱就可以查看发送的邮件了邮件内容如下所示 3. 邮件发送客户端示例编写
下面详细介绍创建该示例的步骤确保DevEco Studio已安装仓颉插件。
步骤1创建[Cangjie]Empty Ability项目。
步骤2在module.json5配置文件加上对权限的声明
requestPermissions: [{name: ohos.permission.INTERNET}]这里添加了访问互联网的权限。
步骤3在build-profile.json5配置文件加上仓颉编译架构
cangjieOptions: {path: ./src/main/cangjie/cjpm.toml,abiFilters: [arm64-v8a, x86_64]}步骤4在index.cj文件里添加如下的代码
package ohos_app_cangjie_entryimport ohos.base.*
import ohos.component.*
import ohos.state_manage.*
import ohos.state_macro_manage.*
import std.collection.HashMap
import std.convert.*
import std.net.*
import std.socket.*
import encoding.base64.toBase64StringEntry
Component
class EntryView {Statevar title: String SMTP邮件发送客户端示例;//连接、通讯历史记录Statevar msgHistory: String //服务器是否响应发送数据到客户端var isServerResponse: Bool false//服务端地址smtp.sohu.com的ip地址为116.130.217.16Statevar serverAddr: String 116.130.217.16//服务端端口smtp.sohu.com的端口为25不同的smtp服务器端口可能不一样Statevar serverPort: UInt16 25//用户名Statevar userName: String youmailsohu.com//密码对于搜狐邮箱这里是独立密码Statevar passwd: String youpassword//收件人邮箱列表如果多个使用逗号分隔Statevar rcptList: String *****sohu.com,****qq.com//发件人邮箱Statevar mailFrom: String youmailsohu.com//邮件标题Statevar mailTitle: String 测试邮件标题//邮件内容Statevar mailContent: String 这是来自鸿蒙的问候//是否正在登录Statevar isLogin: Bool false//是否可以发送邮件Statevar canSend: Bool false//TCP客户端var tcpClient: ?TcpSocket Nonelet scroller: Scroller Scroller()func build() {Row {Column {Text(title).fontSize(14).fontWeight(FontWeight.Bold).width(100.percent).textAlign(TextAlign.Center).padding(10)Flex(FlexParams(justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center)) {Text(SMTP服务器地址).fontSize(14)TextInput(text: serverAddr).onChange({value serverAddr value}).width(100).fontSize(11).flexGrow(1)Text().fontSize(14)TextInput(text: serverPort.toString()).onChange({value serverPort UInt16.parse(value)}).setType(InputType.Number).width(80).fontSize(11)}.width(100.percent).padding(5)Flex(FlexParams(justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center)) {Text(邮箱用户名).fontSize(14).width(100).flexGrow(0)TextInput(text: userName).onChange({value userName value}).width(110).fontSize(12).flexGrow(1)}.width(100.percent).padding(5)Flex(FlexParams(justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center)) {Text(登录密码).fontSize(14).width(100).flexGrow(0)TextInput(text: passwd).onChange({value passwd value}).setType(InputType.Password).width(110).fontSize(12).flexGrow(1)Button(登录).onClick {evt login()}.enabled(!isLogin userName ! passwd ! ).width(70).fontSize(14)}.width(100.percent).padding(5)Flex(FlexParams(justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center)) {Text(收件人邮箱).fontSize(14).width(100).flexGrow(0)TextArea(placeholder: 多个收件人使用逗号分隔, text: rcptList).onChange({value rcptList value}).width(110).fontSize(12).flexGrow(1)}.width(100.percent).padding(5)Flex(FlexParams(justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center)) {Text(发件人邮箱).fontSize(14).width(100).flexGrow(0)TextInput(text: mailFrom).onChange({value mailFrom value}).width(110).fontSize(12).flexGrow(1)}.width(100.percent).padding(5)Flex(FlexParams(justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center)) {Text(邮件标题).fontSize(14).width(100).flexGrow(0)TextInput(text: mailTitle).onChange({value mailTitle value}).width(110).fontSize(12).flexGrow(1)}.width(100.percent).padding(5)Flex(FlexParams(direction: FlexDirection.Column, justifyContent: FlexAlign.Start,alignItems: ItemAlign.Center)) {Text(邮件内容).fontSize(14).width(100.percent)TextArea(placeholder: 请输入要发送的邮件内容, text: mailContent).onChange({value mailContent value}).width(100.percent).height(80).fontSize(12)Row() {Button(发送邮件).onClick {evt sendMail()}.enabled(canSend).width(100).fontSize(14)}.width(100.percent).justifyContent(FlexAlign.End)Scroll(scroller) {Text(msgHistory).textAlign(TextAlign.Start).padding(10).width(100.percent).backgroundColor(0xeeeeee)}.align(Alignment.Top).backgroundColor(0xeeeeee).height(200).flexGrow(1).scrollable(ScrollDirection.Vertical).scrollBar(BarState.On).scrollBarWidth(20)}.width(100.percent).padding(5).flexGrow(1).height(300)}.width(100.percent).height(100.percent)}.height(100.percent)}//发送命令到服务器func sendCmd2ServerWithCRLF(cmd: String) {let fullCmd: String cmd \r\ntcpClient?.write(fullCmd.toArray())msgHistory C:${cmd}\r\n}//从服务器读取消息func readMsgFromServer() {let buffer ArrayUInt8(1024, item: 0)//从socket读取数据var readCount tcpClient?.read(buffer)//把接收到的数据转换为字符串let content String.fromUtf8(buffer[0..readCount.getOrThrow()])msgHistory S:${content}return content}//登录func login() {tcpClient TcpSocket(serverAddr, serverPort)isLogin true//启动一个线程执行登录spawn {try {tcpClient?.connect()msgHistory C:连接成功\r\n} catch (err: Exception) {msgHistory C:连接失败${err.message}\r\nisLogin falsereturn}try {sendCmd2ServerWithCRLF(ehlo anyname)var content readMsgFromServer()sendCmd2ServerWithCRLF(auth login)content readMsgFromServer()sendCmd2ServerWithCRLF(toBase64String(userName.toArray()))content readMsgFromServer()sendCmd2ServerWithCRLF(toBase64String(passwd.toArray()))content readMsgFromServer()canSend true} catch (exp: Exception) {msgHistory 从Socket读取数据错误:${exp}\r\n}isLogin false}}func sendMail() {//启动一个线程执行发送spawn {try {sendCmd2ServerWithCRLF(mail from:${mailFrom})var content readMsgFromServer()for (rcpt in rcptList.split(,)) {sendCmd2ServerWithCRLF(rcpt to:${rcpt})content readMsgFromServer()}//准备发送邮件内容sendCmd2ServerWithCRLF(data)content readMsgFromServer()let mailBody Subject: ${mailTitle} \r\nFrom: ${mailFrom}\r\n\r\n${mailContent}\r\n.sendCmd2ServerWithCRLF(mailBody)content readMsgFromServer()sendCmd2ServerWithCRLF(quit)content readMsgFromServer()} catch (exp: Exception) {msgHistory 从套接字读取数据错误:${exp}\r\n}}}
}
步骤5编译运行可以使用模拟器或者真机。
步骤6按照本文第2部分“邮件发送客户端示例演示”操作即可。
4. 代码分析
本文的核心代码主要是两个函数第一个是发送命令到服务器的函数sendCmd2ServerWithCRLF该函数在发送命令给服务器时会在命令后面添加回车换行符号然后调用tcpClient的write函数执行实际的发送。第二个是从服务器读取消息的函数readMsgFromServer该函数会从套接字读取数据并写入到缓冲区buffer中然后把数据转换为字符串。
需要特别注意的是为了简化开发第二个函数假设可以一次性读取服务器的完整回复并且服务器的回复不超过1024字节这个假设一般是成立的不过在一些特殊情况下比如网络不太好或者网络数据“粘包”可能会出现接收问题。这时候可以通过更复杂的代码来解决这里就不展开了可以参考本系列相关的“TCP粘包”文章。
本文作者原创除非明确授权禁止转载
本文源码地址 https://gitee.com/zl3624/harmonyos_network_samples/tree/master/code/tcp/SmtpClient4Cj
本系列源码地址 https://gitee.com/zl3624/harmonyos_network_samples