使用Python脚本来收发Gmail, Say no to GFW

使用Python脚本来收发Gmail, Say no to GFW

分类: 有意思 程序员 Python   310人阅读  评论(0)  收藏  举报

目录(?)[+]

博主的新站点,看此文章也可以来这里。


学校里面的网络环境一直令人不快,天天喊着要建立国际一流大学,就校园网这质量只能是下辈子的事了,再加上国内目前对Google方面的不友好,我会经常性的不能正常通过浏览器连接到我的Gmail邮箱,捉急的时候真是很后悔当初选择了Gmail,虽然它看起来又高端又时尚又有Geek风范。对Outlook和Mac上自带Mail软件的失望让我有了这一想法,本文里面说到这个版本还处于初级阶段,不过应应急看邮件回复紧急事情肯定是够用了。


废话不多说直接进入正题了,本文将要告诉你的事情是,如果你也想我一样需要一个应急的接收Gmail的小插件,这篇文章可以帮助你在数分钟之内搭建一个收发Gmail的小平台,当然前提是你也和我一样喜欢使用CLI的形式与你的计算机交互。


首先我们先来看看接收邮件的part


如果你想敲几个命令就连上你的邮箱大致需要下面的几个步骤:第一,你要与你的邮箱服务器建立一个成功的连接,当然我使用的是IMAP的协议,个人觉着比POP更好,当然人人都有自己的喜好,这也不是啥关键的事情。第二,在连接成功建立的基础上你要使用自己的帐号和口令成功登陆,也就是去的认证获取对该用户邮箱的操作权。第三,在前两者都OK的基础上你可以开始搞一些事情了,例如获取目前的邮箱一些基本情况(邮件总数,未读数量,已读数量,容量情况),在此基础上你就可以读取某一封邮件了(目前在带有附件,HTML元素,图片的邮件上还比较无力)。


虽然看起来功能弱爆了,但是对我来讲已经足够了,想象一下一个焦急等待面试结果或者等待女朋友是否同意求婚而苦守在邮箱门前却因为GFW的缘故无法得知结果的可怜人的痛苦心情吧!代码的实现大概是这样子的(只贴上关键部分,对于怎么组织所有代码是个太灵活的事情,谁让咱们有那么多模式呢)。


def __init__(self): 
    self.IMAP_SERVER='imap.gmail.com'
    self.IMAP_PORT=993
    self.M = None
    self.respons
    self.mailboxes = [] 
def login(self, username, password): 
    self.M = imaplib.IMAP4_SSL(self.IMAP_SERVER, self.IMAP_PORT) 
    rc, self.response = self.M.login(username, password) 
    return rc 

这部分就是第一步和第二步所做到事情。


def receive_mail(self):       
    recvMail = receiveMail.ReceiveMail(self.M) 
    mailCounts = recvMail.get_mail_count()
    print 'A total of '+ mailCounts +' mails in your input mailbox.'
    print 'A total of '+recvMail.get_unread_count()+ ' UNREAD mails in your input mailbox.'
    recvMail.get_imap_quota()
    mailBody = recvMail.check_simpleInfo(mailCounts) #返回值是邮件content
    if mailBody != 0:
        recvMail.check_detailInfo(mailBody)
    return

上面的这些代码是出现在调用层的,主要是调用了具体实现功能的下面几个函数。


下面的这些则在receiveMail.py文件中。


def check_simpleInfo(self, mailCounts):
    print "Input 'y' to check the lasted UNread mail. Other cmds to abandon!"
    while True:
        argv = string.split(raw_input('$====>'))
        if len(argv)!=0:
            if argv[0] == 'y':
                mailBody = self.get_mail_simpleInfo_from_id(mailCounts)
                return mailBody
            else:
                return 0
        else:
            pass
    else:
        pass

调用check_simpleInfo()函数查阅某邮件的简略信息,包括邮件来自谁,发送时间,主题等。 调用check_detailInfo()函数来查看邮件的详细信息也就是邮件内容。当然都看得出来get_mail_simpleInfo_from_id()才是主要进行了获取内容的工作,下面来看一下这个函数。


def get_mail_simpleInfo_from_id(self, id): 
    status, response = self.M.fetch(id,"(RFC822)")
    mailText = response[0][1]
    mail_message = email.message_from_string(mailText)
    subject = unicode(email.Header.make_header(email.Header.decode_header(mail_message['subject'])))
    mail_from = email.utils.parseaddr(mail_message["from"])[1]
    mail_to = email.utils.parseaddr(mail_message["to"])[1]
    print '['+mail_message['Date']+']'+'\n'+'From:'+mail_from+ ' To:'+mail_to+'\n'+'Subject:'+subject+'\n'
    return self.get_first_text_block(mail_message)

由于我们在工作中会使用到中文,所以在这里我们还需要关注两个有可能产生乱码的地方,一个是邮件头部分在代码中使用了email.Header对其进行解码,email.Header.decode_header(subject)对邮件主体可能出现的乱码进行了处理。关于此处stackoverflow上有一热心的哥们坚定的表示像以往那样只是简单的对他们进行解码是不够的,因为此处的mail_message['subject']有可能回返回多个实体,而不仅仅是一个,所以为了保证数据的完整采用了列表解析循环获取数据,他强烈推荐我使用subject = u''.join(unicode(strs,t) for strs,t in email.Header.decode_header(mail_message['subject'])),从这句代码可以看出python是多么省事儿的语言。但是这里还是不够严密的,那就是有些邮件在发送的时候没有指定明确的编码格式,这就导致了在一定的几率下,email.Header.decode_header()会返回None作为第二个返回值,会造成unicode()的失败,于是此大神在报告bug的时候推荐给我了上面的那句代码,subject = unicode(email.Header.make_header(email.Header.decode_header(mail_message['subject'])))

显然get_first_text_block()函数对邮件的主要内容进行处理,用来判断这个作为参数传进来的邮件实体的主体类型是哪个?如果还是multipart类型还需要继续分解一下最后的目标就是将他们全部分解为text类型。


def get_first_text_block(self,email_message_instance):
    maintype = email_message_instance.get_content_maintype()
    if maintype == 'multipart':
        for part in email_message_instance.get_payload():
            if part.get_content_maintype() == 'text':
                return part.get_payload(decode=True).strip()
    elif maintype == 'text':
        return email_message_instance.get_payload(decode=True).strip()

其中part.get_payload(decode=True)函数对解析的邮件主要内容进行了解码,避免将一些乱七八糟的mojibake直接显示在你的终端里。说到这里不能不再啰嗦一件事,虽然很不起眼但是却很容易再这里出问题,那就是你terminal的编码格式,如果你的编码格式不支持中文或者utf-8的画python会报错的,没错你没有看错,terminal的编码错误会造成python的崩溃,我就遇到了此问题,虽说Mac的terminal是支持各种编码的但是正巧我做这一部分的时候是在使用公司的Thinkpad,于是在window的CMD下就果断悲剧了,直接报了python的编码不能找到定义字符集(UnicodeDecodeError),所以此处是需要注意的。


下面的这个函数其实没有什么必要说的,将其单独拿出来完全是为了业务逻辑上的考虑,此函数中传入的参数就是get_first_text_block()函数的返回值,在调用层的时候将其赋值给了mailBody,可以参见上面的receive_mail函数。


def check_detailInfo(self, mailBody):
    print "Input 'y' to check the detailInfo. Other cmds to abandon!"
    while True:
        args = string.split(raw_input('$====>'))
        if len(args)!=0:
            if args[0] == 'y':
                self.get_mail_content(mailBody)
                return
            else:
                break
        else:
            pass
    else:
        pass    

def get_mail_content(self, content):
    print 'MailContent:'+'\n'+content #直接将内容显示到了终端

上面的代码就是在接受邮件时用到的主要函数,当然还有其他的一些像修改、新增、删除收件箱,按照发送者筛选查询等功能就没有贴上来了。


下面看看创建一个邮件并发送给一个收件列表的主要实现吧


首先我要告诉你的是,想要发一封邮件也需要三个步骤。第一,同样你要成功的连接到邮箱的服务器(我使用的是SMTP协议,这个协议地球人都知道啦估计)。第二,同样要使用自己的信息成功登陆取得权限,在这要多说一点,Gmail的安全验证做的更为完善,普通的SSL不能满足它了,在你连通server之后必须要使用STARTTSL协议来将之前取得连接的SSL来升级为更加安全的加密通道,只有这样才能登陆成功,否则会提示你server的AUTH授权失败。具体的原因有兴趣的还可以参看这篇文章,老外都把事情讲得很详细。第三,此后你就可以畅快的发送邮件了。


def send_new_mail(self):
    send_to_str = raw_input("Input Email address that you want send your mail to,"+'\n'+\
    "if you have multiple address, seperate them with comma."+'\n'+\
    '$===>')
    send_list = send_to_str.split(',')
    send_subject  = raw_input('The Subject of new mail:')
    send_content  = raw_input('The Content of new mail:')
    sendMailInstance = sendMail.SendMail(send_list, send_subject, send_content)
    if sendMailInstance.send_mail():
        print 'New mail send success!'
    else:
        print 'New mail send failed!'
    return

同样上面的代码出现在调用层。实现出现在sendMail.py文件中。


def send_mail(self):  
    me="hello"+"<"+self.mail_user+"@"+self.mail_postfix+">"  
    msg = MIMEText(self.content,'plain','utf-8')  
    msg['Subject'] = Header(self.subject, 'utf-8')
    msg['From'] = me      
    msg['To'] = ";".join(self.send_list)  
    msg['Date'] = email.Utils.formatdate()
    try:  
        smtpServer = smtplib.SMTP()  
        smtpServer.connect(self.mail_host)  
        smtpServer.starttls()
        smtpServer.login(self.mail_user,self.mail_pass)  
        smtpServer.sendmail(me, self.send_list, msg.as_string())  
        smtpServer.close()  
        return True 
    except Exception, e:  
        print str(e)  
        return False  

代码中smtpServer.starttls()此句就是我上提到过的升级安全加密策略的语句,刚知道仅用一句代码就实现的时候还是被Python强大的库惊呆了。其中,不加msg['Date'] = email.Utils.formatdate()这句的话发送出的邮件默认时间为:UTC-07:00 休斯顿、底特律时间,加上之后恢复正常,此问题的原因我还没有详细追究。


从上面的代码不难看出这是能够单纯的发送文本信息的情况,其实其他的像包含HTML和附件和图片的代码也不是很复杂,只是我觉着我现在暂时还用不到,也就没有着急实现。


代码的基本情况大致就是这样了,当然没有逐句的解释这些代码,我觉着逻辑简单命名还算完整,其中有些库函数大家感兴趣的可以Google之,丰富的类库和充足的资料的保证下总体感觉代码开发工作量很小,只能说以后要是再有什么需求就决定继续用Python了,就一个字,方便!快捷!现在下面贴两张我运行的效果图。


选择获取最新的一封邮件:



选择发送一封新的邮件:



你能相信一个菜鸟屌丝学生程序员在一段很短的时间内就从完全没概念到完成编码加debug么?你以为屌丝逆袭了,错,是Python太Powerful了!当然还有更加Powerful的Google在帮我,虽然它时不时上不去还得在.hk .sg .com/ncr之间来回换着用,但Google的存在至少对程序员来说就是个太美好的存在了


Python脚本同时发布新浪微博和twitter

分类: 程序员 Python 有意思   79人阅读  评论(0)  收藏  举报

目录(?)[+]

你可以在博主的新页面同样看到这篇文章


这篇文章我在写第二遍,第一遍写的很详细,可惜因为我很久没用vim了,它生气了,我不小心按错了键,写的好几百行的都没了,这肯定是上天嫌我懒得太久没写了故意来给我这么一下的,好了,不说废话了,下面就是将怎么使用python脚本来在terminal同时更新你在微博和twitter的状态了。


先说微博


首先第一步我们都是要先申请一个开发者的帐号的,关于具体的一些细节可以看看这里,里面讲了授权使用的方式和原理,像我使用的是第三方的SDK,就只是简单的看了一下,没有太深入的了解,不过想要开发SDK的同学还是可以好好研究的。


下面就是代码了:


from weibo import APIClient
from re import split
import urllib,httplib

APP_KEY = '1******671' #youre app key 
APP_SECRET = 'e623c*************bfa30b23' #youre app secret  
# callback url, your must set this URL in your "my application->appInfos-> advanced  info"
CALLBACK_URL = 'http://ww****shore.com'
ACCOUNT = 'bo******@gmail.com'#your email address
PASSWORD = '*********'     #your pw

#for getting the code contained in the callback url
def get_code(url):
    conn = httplib.HTTPSConnection('api.weibo.com')
    postdata = urllib.urlencode     ({'client_id':APP_KEY,'response_type':'code','redirect_uri':CALLBACK_URL,'action':'submit','userId':ACCOUNT,'passwd':PASSWORD,'isLoginSina':0,'from':'','regCallback':'','state':'','ticket':'','withOfficalFlag':0})
    conn.request('POST','/oauth2/authorize',postdata,{'Referer':url,'Content-Type': 'application/x-www-form-urlencoded'})
    res = conn.getresponse()
    location = res.getheader('location')
    code = location.split('=')[1]
    conn.close()
    return code

def post_weibo(post_contents):
    print "weibo posting..."
    #for getting the authorize url
    client = APIClient(app_key=APP_KEY, app_secret=APP_SECRET, redirect_uri=CALLBACK_URL)
    url = client.get_authorize_url()
    code = get_code(url)
    r = client.request_access_token(code)
    access_token = r.access_token # The token return by sina
    expires_in = r.expires_in 
    #save the access token
    client.set_access_token(access_token, expires_in)
    results = client.post.statuses__update(status=post_contents)
    return results

从上面的代码中,有一点需要注意一下那就是,get_code(),这个函数是获取了授权码,在本来的SDK中是没有这一步的,但是少了这一步我们就需要人工的在浏览区的网页上点击连接授权,而我却只想在命令行里面完成所有的事情,所以才有了这个函数,函数中是使用了httplib包模拟了web请求,并且处理了返回的信息,从而获取到了授权码。


之所以没有实现人人网,也是因为授权码的问题,可以看看人人网的开发者文档,授权方式和微博相似,不同就在于不能够我们自己通过代码发送请求来获取授权码,这也就解释了为什么人人网推荐的python SDK都是挂在GAE上的,应该就是因为这个原因,需要我们亲自在网页上进行授权,也正式因为此,我才放弃了人人。其实他们有一个用户名密码端的服务,不过需要填表申请,表我是填了,不过后面就没有消息了,我相信如果我申请成功了,那么就可以使用和微博相同的方式了获取授权码从而获取调用API的tokens了。还是希望有聪明才智的哪位大牛搞成功了,看到这篇文章可以教一下我。


再说Twitter


看了推特的文档才知道美帝的东西就是好,他们用授权方式要更加先进,减少了授权了步骤,使用REST API也使开发者更方便的开发SDK,所以推特的SDK明显要好很多。最受欢迎的tweepy是我的第一次尝试,失败原因至今不是很明确,但因该和我使用的代理有关系,也就是说在国内使用代理上推特和Fb的要注意下,使用tweepy可能会带来的失败。除此之外,还有一点提醒大家需要注意,就是申请的twitter的App是有访问级别的限制的,默认是read only,可以自己改成 read&write 或者 read, write & direct message 都是可以的。


后来我选择的bear的python-twitter包,安装好以后特别好用,使我的代码变的很少了,而且也兼容代理的网络条件,下面是代码:


import twitter
def post_twitter(tweets):
    print "tweets posting..."
    tw_api = twitter.Api(consumer_key='95otEcQ***********xDQQ',
             consumer_secret='1jUeoOHa********************RducGal1iA',
             access_token_key='3171230***********************LQZevkJD5spEi94',
             access_token_secret='2QjrDux***********************VRb7JBKaDGMtmI')
    results = tw_api.PostUpdate(tweets)
    return results

从上面的代码可以看出,这个SDK多么的省事儿,除了让使用者显得没有水平之外再没有别的缺点了。


至于为什么不弄一个Fb版本的,是因为Fb和tw的关系实在是比较暧昧,我绑定了从推特自动同步状态到Fb的服务,所以我的推特一有更新Fb就会跟上,我也就没有必要再做没意义的事情了。


其实我也想把这篇文章好好写写,不过写第二遍确实是有很多不想说了,以后尽量上点干货弥补一下吧。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据提供的引用,"ModuleNotFoundError: No module named 'jpegtran'"错误是由于缺少名为'jpegtran'的模块造成的。根据引用中提供的信息,可以使用Jpegtran提供的Ruby接口来访问jpegtran工具。需要在代码中导入Jpegtran模块,并检查模块是否可用(available)来避免该错误的出现。可以使用以下代码片段作为参考: ``` require "jpegtran" Jpegtran.available? #将返回true或false ``` 另外,根据引用中提到的节点jpegtran,它是一个用于处理JPEG图像的命令行实用程序。如果您在系统的PATH中没有安装jpegtran二进制文件,可以尝试使用提供的二进制文件之一。构造函数可以选择使用jpegtran二进制文件的命令行选项数组。对于在Python使用jpegtran命令行工具的情况,您可以考虑使用subprocess模块来运行命令行命令,并处理任何相关的错误。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [jpegtran-bin-gfw:gfw的jpegtran-bin](https://download.csdn.net/download/weixin_42102272/18613693)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [jpegtran:Ruby接口到“ jpegtran”工具](https://download.csdn.net/download/weixin_42097914/18760108)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [node-jpegtran:jpegtran实用程序作为可读可写流](https://download.csdn.net/download/weixin_42146888/18179127)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值