f6: Pythonista で LINE メッセージ送信


.

/ 2019/10/10 訂正 /
/ [ 1. キッチン ] に Line Messaging API が抜けていた為追加 /

前回記事 [Pythonista でメール送信] 
https://qiita.com/cxfgp/items/4849a856be57646bcf34
の派生
Pythonista で LINE メッセージ送信のテスト

前回記事 同様、テキストエディタに入力
 -> open in -> pythonista
 -> 指定先フレンドへ LINE POST(requests)
 -> バックアップメール送信

以下エラーの場合は、処理スキップしてログ出力、終了
・エラー1: 指定先フレンドNo. 不明
・エラー2: LINE POST NG (HTTP ステータス 200 以外)


補足
・皆様が記事している line messaging api の登録・設定は割愛
・line messaging api + フリープラン -> 1000通/月 制限有
・相手先の公式アカウントに出現する( = フレンドには表示されない)
・フレンドID は事前取得しているもとのする
・テキストメッセージ送信のみ(スタンプその他未対応)


(1) メッセージの入力
　xxx.txt 保存ができるテキストエディタアプリ
　(Textforce や Textastic など)で、以下を入力

　1行目：フレンド指定先 No. (例：1 -> ゆうちゃん、2 -> むうちゃん)
　2行目以降：本文

(2) Open in -> Pythonista のスクリプト呼び出し

(3) コンソール上にて実行



### **[ 1. キッチン ]**


Textforce (テキストエディタアプリ)

Pythonista v2.1.1

iphone SE / ios 9.3.5
iphone 5s / ios 12.1.4

Line Messaging API

### **[ 2. 仕込 ]**


```python:text-open-curl.py

# coding: utf-8

import os
import appex
import shutil
import console

import sys
import datetime

import smtplib
from email.MIMEText import MIMEText
from email.Utils import formatdate
from email.Header import Header

import logging

# ログ出力設定(例：txt-open-curl.log という空ファイルをソース同階層に事前設置しておく)
formatter = '%(asctime)s: %(message)s'
logging.basicConfig(filename='./txt-open-curl.log', level=logging.DEBUG, filemode='a', format=formatter, datefmt='%Y-%m-%d %H:%M:%S')

import json
import requests

# アクセストークン
ctokens = 'MxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxU='

# LINE プッシュ先
url = 'https://api.line.me/v2/bot/message/push'

# =============================
# フレンド 1: ゆうちゃん
to01a = 'Uxxxxxxxxxxxxxx1';
to01b = 'yuu';

# フレンド 2: むうちゃん
to02a = 'Uxxxxxxxxxxxxxx2';
to02b = 'muu';

# FROM メールアドレス
dk01 = 'FROM@mailaddress.com'

# TO メールアドレス
dk03 = 'BACKUP@mailaddress.com'

# =============================

# 日付時刻取得
now1 = datetime.datetime.now()
now2 = '{0:%Y/%m/%d %H:%M:%S}'.format(now1)

cpedf1 = ''
cpedf2 = ''
cpedf3 = ''
cpedf4 = ''
cpedf5 = ''

# yes/no 確認定義
def yes_no_input():
    while True:
        choice = raw_input("'yes' or 'no' [y/n]: ").lower()
        if choice in ['y', 'ye', 'yes']:
            return True
        elif choice in ['n', 'no']:
            return False

# テキストアプリ -> open in -> pythonista /Shared/
# に テキストファイルをコピー後、ファイル名を取得(cpedf1)
def main():
	FILE = appex.get_file_paths()
	PYPATH = os.path.abspath(os.path.dirname(__file__))
	while os.path.basename(PYPATH) != 'Documents':
		PYPATH = os.path.abspath(os.path.join(PYPATH, os.pardir))
	PYPATH = os.path.join(PYPATH, 'Shared')
	if not os.path.isdir(PYPATH):
		os.mkdir(PYPATH)

	for i in FILE:
		if os.path.isfile(i):
			NAME = os.path.basename(i)
			shutil.copyfile(i, os.path.join(PYPATH, NAME))
			global cpedf1
			cpedf1 = NAME
			global cpedf2
			cpedf2 = cpedf1[0:2]
			print(i+'---->'+os.path.join(PYPATH, NAME))
		if os.path.isdir(i):
			shutil.copytree(i, PYPATH)

if __name__ == '__main__':
	if appex.is_running_extension():
		main()
	else:
		console.alert('Error Occured', 'Please launch from extension', 'ok', hide_cancel_button=True)

print ''
print 'ファイル名: ' + cpedf1
print  ''


ie1 = 0
ie2 = ''
ie3 = ''
ie8 = ''
ie9 = ''

iu1 = 0
iu5 = ''
iu8 = ''

# テキストファイルを読み込み
# 1行目 指定フレンドNo.(例 1 -> ゆうちゃん、2 -> むうちゃん)
# 1行目 指定フレンドNo. 登録外文字列の場合はエラー -> フレンド指定先不明 としてログ出力
# (iu3: 指定フレンドNo., iu5: 本文)
cpedf3 = './Shared/'
with open(cpedf3 + cpedf1) as linef:
	for linm in linef:
		iu8 = iu8 + linm
		iu3 = linm.strip()
		if iu1 == 0:
			if iu3 == '1':
				ie1 = 1
				ie3 = to01b
				ie2 = to01a
			elif iu3 == '2':
				ie1 = 2
				ie3 = to02b
				ie2 = to02a
			else:
				ie1 = 99
				ie3 = 'フレンド指定先不明'
				ie2 = iu3
		else:
			iu5 = iu5 + linm
		iu1 = iu1 + 1
linef.close()


# if: LINE POST、else: エラー1 フレンド指定先不明
if ie1 != 99:
	ie9 = 'OK: TO ' + ie3
	# メール送信先
	TO = dk03
	# メール件名
	cpedf4 = 'pythonista LINE to ' + ie3 + ' - ' + now2
	# メール本文
	cpedf5 = iu5 + '\n'
	# LINE CURL
	data = { "to": ie2, "messages": [{ "type": "text", "text": iu5 }] }
else:
	ie9 = 'NG1: TO ' + ie3 + ' - ' + ie2
	TO = 'no mail'


# コンソール確認用(ie1 = 指定フレンドNo. / TO = 送信先メールアドレス)
print 'ie1: ' + str(ie1) + ' / ' + ie9
print TO
print ''

# yes/no 選択
# POST(requests): ステータス 200 なら バックアップメール送信
# POST(requests): 一応 ステータス 200 チェック、allow_redirects=False としているが、念のため history 表示
if yes_no_input():
	print 'yes 選択: LINE POST'
	print ''
	if ie1 != 99:
		logging.info('%s %s', 'POST スタート to', ie3)
		headers = {'Content-Type': 'application/json; charset=utf-8', 'Authorization': 'Bearer ' + ctokens}
		resp = requests.post(url, data=json.dumps(data).encode("utf-8"), headers=headers, allow_redirects=False)
		hist = resp.history
		stcd = resp.status_code
		print 'ヒストリー: ' + str(hist)
		print 'ステータス: ' + str(stcd)
	else:
		logging.info('%s %s', 'test', ie9)
		logging.info('%s %s', '', '')
		print 'フレンド先不明、POST/メール中止 - 終了'
		print ''
		sys.exit()
	if stcd == 200:
		print 'POST 完了'
		print ''
		FROM = dk01
		CC = ['', '']
		CC_ADD = ', '.join(CC)
		BCC = '' 
		ENCOD = 'utf-8'
		logging.info('%s %s', 'メール送信 to', dk03)
		message = MIMEText(cpedf5.encode(ENCOD), 'plain',ENCOD,)
		message['Subject'] = str(Header(cpedf4, ENCOD))
		message['From'] = FROM
		message['To'] = TO
		message['Cc'] = CC_ADD
		message['Date'] = formatdate()
		s = smtplib.SMTP('smtp.gmail.com', 587)
		s.ehlo()
		s.starttls()
		s.ehlo()
		s.login(dk01, 'PASSWORD')
		s.sendmail(FROM, [TO, CC_ADD, BCC], message.as_string())
		s.close()
		logging.info('%s %s', 'test', ie9)
		logging.info('%s %s', '', '')
		print '処理完了 - 終了'
		print ''
		sys.exit()
	else:
		ie8 = 'NG2: POST NG ステータス: ' + str(stcd)
		logging.info('%s %s', 'test', ie8)
		logging.info('%s %s', '', '')
		print 'POST NG ステータス: ' + str(stcd)
		print ''
		print 'メール送信中止 - 終了'
		print ''
		sys.exit()
else:
	logging.info('%s %s', 'test', 'キャンセル 終了')
	logging.info('%s %s', '', '')
	print 'no 選択: キャンセル - 終了'
	print ''
 	sys.exit() 


```



### **[ 3. デザート ]**


Line アプリを使用しない人向け

Line 問わず、いままで web サーバーを介して curl をしていた為、
iOS ローカル(Pythonista)で curl post が気軽にできるのは吉


以下、前回記事同様

※ 簡易的ざっくり作成なので
   プロセスエラーや細かなエラーは拾ってません

※ Pythonista v3 未確認(多分いけると思います)

※ メール送信元が gmail の場合は
「安全性の低いアプリの許可」-> 有効 が必要です

.