文章目录
- 0.引言
- 1.获取外网IP
- 2.打开SMTP服务
- 3.python发送邮件
- 4.完整代码
0.引言
\qquad之前一直使用Putty连接公司的PC机进行远程办公,苦于外网的IP地址不能固定下来,所以购买了内网穿透服务,免费版还会限速。后来转念一想,如果能定时获取PC机的外网IP并发送到自己的设备上,不就不需要内网穿透服务了吗,于是就有了本文。需要远程办公的朋友们建议收藏。
1.获取外网IP
\qquad获取外网IP的方式有很多种,直接通过命令行或者登录网页即可:
Linux下获取外网IP
Windows下获取外网IP
\qquad你可以利用shell命令定时获取IP并执行一个发送邮件的python文件,但是这样太过繁琐,于是我将获取IP的方式整合到了python中(其实是参考了别人的博客,但是回头找真的找不到是哪篇了,在此还是感谢这位博主,因为它的方法确实比其他人的简单)
from urllib.request import urlopen
my_ip = urlopen('http://ip.42.pl/raw').read()
my_ip = my_ip.decode(encoding='utf-8') # ip str
这样就会返回string类型的IP地址了,需要注意的是获取频次不能太快(>10s),timeout也不宜太小(>3s),否则可能会报urlopen.error。
2.打开SMTP服务
\qquadpython邮件发送属于第三方服务,需要邮箱开启SMTP服务,以QQ邮箱为例,网易的和学校公邮一般也有这个功能,代码也是通用的。
第一步:在设置中找到账户
第二步:找到SMTP服务,点击开启(需要手机向一个号码发送短信,是要钱的,不过也就一条短信费用)。
最好把授权码复制下来,不然还得再花一次冤枉钱再发一次。
授权码一定不能泄露!不放心的朋友最好设置自己不常用不绑定信息的邮箱作为测试邮箱。
3.python发送邮件
\qquad打开SMTP服务之后的邮箱可以作为发送邮箱,而接收邮箱则不需要其打开SMTP服务,只需要知道邮箱号即可。以下是一个例子,其实发送者不是QQ邮箱也行,只要是打开过SMTP服务的就可以。
def send_email(): host_server = 'smtp.qq.com' #qq邮箱smtp服务器sender_qq = 'xxxxx@qq.com' #发件人邮箱pwd = "xxxxxxxxxx" # 授权码 str格式receiver = ['xxxxx@qq.com','xxxxx@qq.com']#收件人邮箱mail_title = 'Python自动发送的邮件' #邮件标题mail_content = "您好,这是python自动发送的邮件,请查收。"#邮件正文内容# 初始化一个邮件主体msg = MIMEMultipart()msg["Subject"] = Header(mail_title,'utf-8')msg["From"] = sender_qq# msg["To"] = Header("测试邮箱",'utf-8')msg['To'] = ";".join(receiver)# 邮件正文内容msg.attach(MIMEText(mail_content,'plain','utf-8'))smtp = SMTP_SSL(host_server) # ssl登录# login(user,password):# user:登录邮箱的用户名。# password:登录邮箱的密码,像笔者用的是网易邮箱,网易邮箱一般是网页版,需要用到客户端密码,需要在网页版的网易邮箱中设置授权码,该授权码即为客户端密码。smtp.login(sender_qq,pwd)# sendmail(from_addr,to_addrs,msg,...):# from_addr:邮件发送者地址# to_addrs:邮件接收者地址。字符串列表['接收地址1','接收地址2','接收地址3',...]或'接收地址'# msg:发送消息:邮件内容。一般是msg.as_string():as_string()是将msg(MIMEText对象或者MIMEMultipart对象)变为str。smtp.sendmail(sender_qq,receiver,msg.as_string())# quit():用于结束SMTP会话。smtp.quit()
4.完整代码
\qquad以下例程,填好抬头的必要信息之后就可以直接运行了。注意文件名不要取email.py,会和email模块冲突!最后提醒大家方便自己远程办公的同时也要保护好自己的个人信息,尤其是授权码。
\qquad获取IP的速度是10s一次,可以通过修改对应注释的Timer定时器的数值(单位:s)调整,默认模式是监测到PC机的外网IP变化时向指定邮箱发送。为防止出现urlopen.error终止程序,还得加上异常处理,如下图即是工作中可能出现的异常:
# -*- coding: utf-8 -*-
from smtplib import SMTP_SSL
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.header import Headerfrom urllib.request import urlopen
import threading
import datetime
import sys
# smtplib模块主要负责发送邮件:是一个发送邮件的动作,连接邮箱服务器,登录邮箱,发送邮件(有发件人,收信人,邮件内容)。
# email模块主要负责构造邮件:指的是邮箱页面显示的一些构造,如发件人,收件人,主题,正文,附件等。
my_ip = urlopen('http://ip.42.pl/raw',timeout=5).read()
my_ip = my_ip.decode(encoding='utf-8')
sender_qq ='xxxx@qq.com' # 发送邮箱
receiver = ['xxxx@qq.com','xxxx@qq.com'] # 接收邮箱
pwd = "xxxxx" # 授权码
def send_email(my_ip,time=None): host_server = 'smtp.qq.com' #qq邮箱smtp服务器mail_title = 'Python自动发送的邮件' #邮件标题mail_content = "外网IP:{}\n发送时间:{}".format(my_ip,time) #邮件正文内容# 初始化一个邮件主体msg = MIMEMultipart()msg["Subject"] = Header(mail_title,'utf-8')msg["From"] = sender_qq# msg["To"] = Header("测试邮箱",'utf-8')msg['To'] = ";".join(receiver)# 邮件正文内容msg.attach(MIMEText(mail_content,'plain','utf-8'))smtp = SMTP_SSL(host_server) # ssl登录# login(user,password):# user:登录邮箱的用户名。# password:登录邮箱的密码,像笔者用的是网易邮箱,网易邮箱一般是网页版,需要用到客户端密码,需要在网页版的网易邮箱中设置授权码,该授权码即为客户端密码。smtp.login(sender_qq,pwd)# sendmail(from_addr,to_addrs,msg,...):# from_addr:邮件发送者地址# to_addrs:邮件接收者地址。字符串列表['接收地址1','接收地址2','接收地址3',...]或'接收地址'# msg:发送消息:邮件内容。一般是msg.as_string():as_string()是将msg(MIMEText对象或者MIMEMultipart对象)变为str。smtp.sendmail(sender_qq,receiver,msg.as_string())# quit():用于结束SMTP会话。smtp.quit()def ip_render():global my_ipglobal timertry:date_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')new_ip = urlopen('http://ip.42.pl/raw').read()new_ip = new_ip.decode(encoding='utf-8')if new_ip != my_ip:my_ip = new_ipsend_email(my_ip,time=date_time)print('IP changed:{} -time:{}'.format(my_ip,date_time))else:sys.stdout.write("\rIP doesn't change -time:{}".format(date_time))sys.stdout.flush()except Exception as e:print("Exception:{}".format(e))timer = threading.Timer(30, ip_render) # 30s 获取IP一次timer.start()
if __name__ == "__main__":print('IP:{}'.format(my_ip))timer = threading.Timer(5, ip_render) # 5s后开始循环线程timer.start()
希望本文对您有帮助,谢谢阅读!