@yardbirds7541

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

Linux daemonからGmailを送信したい

Pythonで書いたGmail送信をdeamonから実行したい。

プロンプトから実行して、Gmail送信できることは確認できました。
このPythonスクリプトをサービスに登録して、daemonから動かすと、送信されません。

デバックの方法、送信されない理由を調べる方法等があれば教えてほしいです。

#ソース

mail_send.py
import string
import time
import os
import sys
import datetime
import dateutil
from dateutil.relativedelta import relativedelta
import boto3
import smtplib
from email.mime.text import MIMEText
from email.header import Header
from email.utils import formatdate

accesskey = "xxxxxxxxxxxxxxxxxxxx"
secretkey = "xxxxxxxxxxxxxxxxxxxx"
region = "ap-northeast-1"

def sendShortMessage(title,msg):
	print("send to iPhone")
	boto3.set_stream_logger()
	try:
		#print("client")
		sns = boto3.client("sns", aws_access_key_id=accesskey, aws_secret_access_key=secretkey, region_name=region)	
		#print("publish")
		response = sns.publish(PhoneNumber = "+81xxxxxxxxxxxx",Subject = title,Message = msg)
		#print("response")
	except Exception as err:
		print(err.code)

def sendMsg_eMail(from_address, to_address, cc_address, subject, body, encode):
	gmail_pass="app-passwd"
	SMTP="smtp.gmail.com"
	PORT=587
	msg=MIMEText(body,"plain",encode)
	msg["From"]=from_address
	msg["To"]=to_address
	msg["Subject"]=Header(subject, encode)

	try:
		print("mail Sending now...")
		send = smtplib.SMTP(SMTP,PORT)
#		send.set_debuglevel(True)
		send.ehlo()
		send.starttls()
		send.ehlo()
		send.login(from_address,gmail_pass)
		send.send_message(msg)
		send.close()
	except Exception as e:
		print("except: "+str(e))
	else:
		print("{0} send message.".format(to_address))

def start_mail_send():
	date_start = datetime.date.today()
	mail_to="xxxxxxxxx@yahoo.co.jp"
	mail_from="yyyyyyyyyyy@gmail.com"
	mail_cc="zzzzzzzzzz@i.softbank.jp"
	mail_subject="test report start"
	mail_body="service start " + date_start.strftime('%Y/%m/%d')
	mail_encode="utf-8"

	sendMsg_eMail(mail_from, mail_to, mail_cc, mail_subject, mail_body, mail_encode)

def main_unit():#10秒おきに時刻を書き込む
	#print("test start")
	start_mail_send()
	
	counter = 2
	
	while counter > 0:
		filepath = '/home/orca/test.log'
		log_file = open(filepath,'a')
		try:
			log_file.write(time.ctime()+"\n")
		finally:
			log_file.close()
		time.sleep(10)
	
	print("test end.")

def daemonize():
	pid = os.fork()#ここでプロセスをforkする
	if pid > 0:#親プロセスの場合(pidは子プロセスのプロセスID)
		pid_file = open('/home/orca/python_daemon.pid','w')
		pid_file.write(str(pid)+"\n")
		pid_file.close()
		sys.exit()
	if pid == 0:#子プロセスの場合
		main_unit()
        
if __name__ == "__main__":
	while True:
		daemonize()

#サービス登録
#/usr/lib/systemd/system/mail_send.service

mail_send.service
[Unit]
Description=mail send

[Service]
Type=simple
Restart=on-failure
RestartSec=10s
WorkingDirectory=/home/orca
ExecStart=/usr/bin/python3 -m mail_send.py

[Install]
WantedBy=multi-user.target

systemctl コマンドでpythonスクリプトサービスを実行する。

0 likes

3Answer

今のままでは読む気になりません。コードブロックを正しく使って示してください。「プレビュー」で自分が書いたmarkdownの出力を確認しましょう。

0Like

Comments

  1. @yardbirds7541

    Questioner

    追加情報です。
    ことし、4月ごろだったと思うのですが、daemonから送信できていました。
    google側のセキュリティポリシーの変更で、googleアカウントからアプリパスワードを発行しています。
    その結果、コンソールからGMAIL送信は回復しましたが、これをdaemonとして動かすと送信できません。

  2. @yardbirds7541

    Questioner

    すみません、回答遅くなりました。
    ありがとうございます。
    追加調査等に手間取りました。

    https://support.google.com/a/answer/12158207?hl=ja
    このアナウンス以降に、動いてたメール自動送信daemonからメールが来なくなり、Gmailアカウントからアプリパスワードを取得しなおしました。
    その取り直したパスワードを使って、ログイン状態から

    python アプリ名.py
    で実行すると、メール送信できました。
    以前ならそのまま、daemon化すれば送信できていたのですが、今はできません。

    ログを増やして、確認したところ、

    '''mai_send
    try:
    print("mail Sending now...")
    send = smtplib.SMTP(SMTP,PORT)
    send.ehlo()
    send.starttls()
    send.ehlo()
    send.login(from_address,gmail_pass)
    send.send_message(msg)
    send.close()
    except Exception as e:
    print("except: "+str(e))
    '''
     上記のsend = smtplib.SMTP(SMTP,PORT)の行以降、ehlo、startttls、loginのどれをやっても、実行されず、例外ハンドラにかからずにプロセス終了していることが確認できました。
     サービスの記述にUser、Groupを追加したりしてみましたが、状況は変わりませんでした。

ExecStart=/usr/bin/python3 -m mail_send
ExecStart=/usr/bin/python3 mail_send.py

モジュール起動は py有りで動きます?

Restart=on-failure
RestartSec=10s

の指定が勿体ないです。try無しでフォアグラウンド実行の方が良いのでは?

または、crontab -e に登録してはどうでしょう?

ログはsyslogに吐き出した方が落ちる確率をさげますよ。

0Like

Comments

  1. @yardbirds7541

    Questioner

    pyありで、起動しています。ログで確認しています。

    ExecStart=/usr/bin/python3 -m mail_send.py
    の-mをとると、アクティブにならないですね。
    '''
    test@raspberrypi:~$ sudo systemctl status mail_send.service
    ● mail_send.service - mail_send
    Loaded: loaded (/lib/systemd/system/mail_send.service; enabled; vendor preset: en
    Active: active (running) since Fri 2023-08-04 16:05:22 JST; 2s ago
    Main PID: 9852 (python3)
    Tasks: 1 (limit: 877)
    CGroup: /system.slice/mail_send.service
    mq9852 /usr/bin/python3 -m mail_send.py

    Aug 04 16:05:22 raspberrypi systemd[1]: Started mail_send.

    '''

  2. if __name__ == "__main__":
    	while True:
    		daemonize()
    

    while True:によるpid_fileのファイルディスクリプタの枯渇でしょうか?

    そもそも、pid = os.fork()のみでは完全にdaemonizeされてません。デバイスの切り離しプロセスがありません。

    暫定対処

    1. Type=simpleを Type=forking に変更(これが起動直後、正常扱いされた理由)
    2. #Restart=on-failure コメント化による再起動させない。
    3. #RestartSec=10s コメント化
    4. #while True: コメント化
    5. pid_file関連もコメント化
    6. test.log関連もコメント化し、多くのprint文を挿入する。
    7. systemctl restart mail_send にてエラーを目視
    8. 可能なら、OSのリブートを実行

    恒久対処 os.fork()しない

  3. @yardbirds7541

    Questioner

    @HalHarada様、os.fork()しないで、gmail送信確認できました。
    ありがとうございます。

    初期のプロンプトから実行するとGmailが送信できるのに、サービスから送信できない、は、解決しました。

    サービスの起動は確認できましたが、ステータスで見るとタイムアウトエラーをしているので、サービスの記述は、まだ修正が必要な様です。

    元々、Raspi上で定期的にメールを送信するサービスを動かしていたのですが、送信が止まりました。
    https://support.google.com/accounts/answer/6010255?sjid=4568603454312297049-AP
    Gmailが、ユーザー名とパスワードのみでのログインができなくなっていました。
    パスワードを、アプリパスワードに置き換えるだけで、再開するものと思ったのですが、なぜか動かず、一旦、gmail送信を切り離して、logのみを書き出すdaemonにしてみました。
    https://qiita.com/QUANON/items/71f606216f84371a0d04
    その際、os.fork()等を参考としていました。

    なお、大本の参照ネタは、以下の記事です。
    https://qiita.com/maitech/items/9cda9861fd59453fd66e

システムログを全部確認なさるように。
エラーが出てるなら対処の方法も出てくるでしょう。

プロンプトから実行して、Gmail送信できることは確認できました。

この正しく動作した時の実行ユーザーは?

このPythonスクリプトをサービスに登録して、daemonから動かすと、送信されません。

UserGroupが省略されてることからrootユーザーで実行され、かつ実行環境が変わってる可能性があります。


余談ですが恐らくこのような記事を観られてるのかと思います。

その記事のコメント欄でも指摘されてますが、普通systemdに対してpidファイルを作る優しさは不要なのです。
その分省けばシンプルなコードになるはずですが…。

0Like

Your answer might help someone💌