Python2.7からGmailを送信する
研究室で毎週特定の曜日(水曜日)の特定の時間にお知らせメールを送信する仕事を任されていて、いままでは前日の毎週火曜日にRight Inboxを使って送信設定していたが面倒になった + Right Inboxの無料枠を使い潰したくないので、Gmailを送信するPythonスクリプトを作ってそれをcronから叩くようにした。備忘録として手順を残しておきます。
Google API Client Libraryを使って、PythonからGmailを送信
今回は、Google API Client Libraryという各言語から各種APIにアクセスする用のライブラリを使った方法を書いていきます。
Gmailを送信するまでの手順
GmailをPythonから送信するまでには、OAuthの認証周りを含む以下のような手順が必要です。
- Google Developer Consoleから新しいプロジェクトを作成し、OAuthクライアントIDを取得する
- authorization codeを取得する
- authorization codeをアクセストークンとリフレッシュトークンと交換する
- メールを送信する
新しいプロジェクトを作成し、OAuthクライアントIDを取得する
Google Developer Consoleから新しいプロジェクトを作ったら、API Managerの認証情報 -> 認証情報を作成 -> OAuthクライアントID を選択し、クライアントIDとクライアントシークレットを作成します。
次に出てくる「アプリケーションの種類」の部分では、今回はPythonスクリプトからAPIを叩くので「その他」を選択してください。
これで、クライアントIDとクライアントシークレットを取得することができました。
次に、Pythonからプロジェクトの情報を利用するための設定ファイル client_secrets.json
を作成します。
{ "web": { "client_id": "クライアントID", "client_secret": "クライアントシークレット", "redirect_uris": [], "auth_uri": "https://accounts.google.com/o/oauth2/auth", "token_uri": "https://accounts.google.com/o/oauth2/token" } }
使い捨てみたいなスクリプトをつくるんならわざわざファイルを分けずにハードコードしてもいいんじゃない?って思うかもしれないけれど、OAuth認証をするライブラリ oauth2client
がファイルから情報を読むようになっているので、ファイルに書いておいたほうが無難です。(あとでコードを公開することになったときにヘタをこくのも防止できる)
authorization codeを取得する
ここからは、Python上の作業になります(すこしブラウザ操作も入りますが…)。
authorization codeとは、アクセストークンとリフレッシュトークン(後述)を取得するために一度だけ使うトークンのようなものです。一度アクセストークンを取得するために使い終わると、そのauthorization codeはもう使うことができません。
def retrieve_authorize_code(flow): auth_url = flow.step1_get_authorize_url() webbrowser.open(auth_url) # ブラウザで認証画面を表示 exit(0) ~~~ """Main""" flow = client.flow_from_clientsecrets( "client_secrets.json", scope = "https://www.googleapis.com/auth/gmail.send", # メール送信の権限を取得する redirect_uri = "urn:ietf:wg:oauth:2.0:oob") # authorization codeをブラウザ上に表示 retrieve_authorize_code(flow)
flowとは、OAuthの処理の流れを制御するオブジェクト…のようなものです。OAuthとflowについては、Google Client LibraryのOAuthのガイドページにあるスライドがとても簡潔にまとめられていてわかりやすいです。
さて、retrieve_authorize_code(flow)
を実行すると、ブラウザが立ち上がり認証画面が表示されます。
ここで「許可」をクリックすると、画面上にauthorization codeが表示されます。
このcodeをコピーしてとっておきましょう。
実行したコードは、webbrowser.open(auth_url)
のところで止まっています。Ctrl-c
で一度中断してください。codeを取得してコード上に埋め込んだら(次のステップでやります)、retrieve_authorize_code(flow)
はもう不要です。コメントアウトするなりしましょう。
authorization codeをアクセストークンとリフレッシュトークンと交換する
取得したauthorization codeを使って、アクセストークンとリフレッシュトークンを交換します。リフレッシュトークンとは、アクセストークンの期限が切れた際に、新しいアクセストークンを取得するのに使われるトークンです。
def retrieve_credential(flow): auth_code = "auth_code" credential = flow.step2_exchange(auth_code) #with open("credential.pickle", "w") as fpickle: # pickle.dump(credential, fpickle) #with open("credential.pickle", "r") as fpickle: # credential = pickle.load(fpickle) return credential
auth_code
のところにauthorization codeを書いてください。
flow.step2_exchange(auth_code)
にauthorization codeを渡すだけでアクセストークンとリフレッシュトークンが入ったcredentialが取得できます。このcredentialはメール送信をする際に使いまわすので、DBなどに保存してください。今回は簡単にpickleで保存しました。(oauth2clientのStorage.locked_put()
というのを使うのがスジらしいけどなぜか自分の環境ではうまく動かなかったのでこの方法になりました。)
メールを送信する
やっとメール送信です。
def create_service(credential): http_auth = credential.authorize(httplib2.Http()) return build("gmail", "v1", http=http_auth) def create_mail(message_text, subject, to, from_): message = MIMEText(message_text) message["subject"] = subject message["to"] = to message["from"] = from_ return {"raw": base64.urlsafe_b64encode(message.as_string())} def send_mail(service, raw): try: message = service.users().messages().send(userId="me", body=raw).execute() print "A message sent. Id: {}".format(message["id"]) except errors.HttpError, error: print "An error occurred: {}".format(error) ~~~ flow = client.flow_from_clientsecrets( "client_secrets.json", scope = "https://www.googleapis.com/auth/gmail.send", redirect_uri = "urn:ietf:wg:oauth:2.0:oob") credential = retrieve_credential(flow) service = create_service(credential) message_text = "hello, world!" subject = "test subject" to = "example@gmail.com" from_ = "example@gmail.com" mail = create_mail(message_text, subject, to, from_) send_mail(service, mail)
疲れたので続きはあとで追記します…
ビットコインを買ってみた
TL;DR
ビットコイン買ってみたら増えた
特に理由はないんだけど、なんか目新しいことをしたくなってビットコインを買ってみた。ブロックチェーンとか仮想通貨とかそういう周辺のことにちょっと興味があったというのもある。
使ったサイトはコインチェックというサイト。ここは決済にクレカが使えるとかいろいろ利点があった気がする(よく覚えてない)。
まったく知らなかったんだけど、暗号通貨にはビットコイン以外にも何種類もあるらしく、コインチェックではそれらも扱っているらしい。知らない世界だ。ビットコイン以外だとモナーコインくらいしか知らなかった。
いきなり増えた
数日前ここでビットコイン15000円分買ってそのまま放置してみたところ、1000円増えて16000円になった。7%くらい増えた計算。なにやらちょうど暗号通貨に関する大きいカンファレンスがあるらしく、各種仮想通貨の価格が荒れているらしい?
長期保有も手では?
暗号通貨って、ネット通販とか送金とか、これからいろんなところで使われるようになると思う。実際いろんな銀行とか小売企業がビットコインについて言及したり、実際に使えるようになったりしている。すると、信用が増して全体的に値段があがるのではないか…と思う。短期的には急騰、急落はあるだろうけど、ベースラインになる値段は右肩上がりになるはず。とすると、今のうちに買っておいて年単位で持っておけばいい感じに利益がでるのでは?
って思うけど、経済も暗号通貨もド素人の意見なのでなんともいえない。
とりあえず最初に入れた15000円分はそのまま持っといてどうなるのか観察したいと思う。上がればラッキー、下がれば勉強代ということで。
ラズパイはSELinuxが(デフォルトでは)使えない
TL;DR
ラズパイのカーネルはSELinuxの設定をせずにコンパイルされている
環境
- Raspberry Pi 3
- CentOS 7.2
$ uname -a Linux centos-rpi3 4.4.15-v7+ #897 SMP Tue Jul 12 18:42:55 BST 2016 armv7l armv7l armv7l GNU/Linux
概要
外部公開を予定しているラズパイのSELinuxの設定をしようと何気なくgetenforce
したところ、
$ getenforce Disabled
デフォルトでDisabledだと…!
いやな予感がする。
とりあえずpermissiveにしようと/etc/selinux/config
を編集
# This file controls the state of SELinux on the system. # 1= can take one of these three values: # enforcing - SELinux security policy is enforced. # permissive - SELinux prints warnings instead of enforcing. # disabled - No SELinux policy is loaded. SELINUX=permissive #→ disabledになっていたので変更
で、再起動してみたものの…
$ getenforce Disabled
なぜ???
disabledからpermissiveに変更したときに実行されるはずのラベリングも走っている様子がない。。
/.autorelabel
というファイルを作っておけば再起動時にラベリングしてくれるらしいので試してみるが…やはり応答なし。
setenforce
はdisabledのときは(たしか)使えないため
$ setenforce 0 setenforce: SELinux is disabled
うーん…
SELinuxを触るのは初めてなのでなにか見落としが…?と思ったがとくにそういう気配もなく。
調べていると、こんな記事を発見
SELinux requires kernel support, and the default Raspberry Pi kernel does not include it.
カーネルがサポートしてない(╯•﹏•╰)
SELinuxを有効にしたければ自分でカーネルをコンパイルして入れなければならないとのこと。
[Guide] SELinux {Get/Install/Setup} - Raspberry Pi Forums
ここに詳しい設定・コンパイルの仕方が書いてあるので、まぁヒマができたらやってみようかなぁ…とりあえず後回しで。