本ページはプロモーションが含まれています。
毎朝決まった時刻にスクレイピングして、結果をメールで受け取りたい。スクリプトは書けたのに、どこで動かすかで迷っていませんか。cronでメール通知をするだけなら、高いVPSも常駐も要りません。ただし、契約してから「メールが届かない」で詰まることがあります。原因は25番ポートの扱いです。この記事では、今の書き方である「587番+SMTP認証」のPythonコードを紹介します。あわせて、エックスサーバー・VPS・自宅PCの選び方を2026年11月時点の料金と受付状況つきで整理します。
1日1回のメール通知を置く場所:手元PC・エックスサーバー・VPS・自宅回線の比較
「1日1回動かして、結果をメールで送る」処理に必要なものは3つだけです。決まった時刻に起動する仕組み(cron)、Pythonが動く環境、そしてメールを送り出せる経路です。常駐プロセス(ずっと起動し続けるプログラム)も、root権限(サーバー全体の管理者権限)も要りません。この前提で各環境を比べると、次のようになります。
置き場所 | cron | 常駐 | root権限 | メール送信で詰まりやすい点 | 止まる条件 |
|---|---|---|---|---|---|
手元のPC | OSの機能(タスクスケジューラ等)で可 | 可 | あり | 自宅回線では25番ポートでの外部送信が塞がれていることが多い(OP25B) | 電源断・スリープ・OS更新後の再起動・回線断 |
共有レンタルサーバー | サーバーパネルから設定 | 不可 | なし | 契約にメール機能があれば、同じサーバーのSMTPを使える | 実行時間・リソースの制限で強制終了される |
VPS | 自分でcrontabを書く | 可 | あり | 25番ポートの扱いは事業者・契約ごとに確認が必要 | OS・セキュリティ更新を放置した場合や、事業者側のメンテナンス |
自宅サーバー(ミニPC等) | 自分で設定 | 可 | あり | 手元PCと同じくOP25Bの影響を受ける | 停電・回線断・ハードウェア故障 |
OP25B(Outbound Port 25 Blocking)は、家庭向けの回線から外部のメールサーバーへ25番ポートで直接送るのを止める仕組みです。迷惑メール対策として導入されています。自宅で動かすなら、25番ポートで直接送る書き方は最初から捨てるのが前提です。
料金と新規受付の状況(2026年11月時点)
2026年10月中旬には、Linuxカーネルの脆弱性(CVE-2026-99999)への対応で、国内の主要VPSが相次いで新規受付を止めました。今は「安いかどうか」より先に「今日契約できるか」を確認する必要があります。
サービス | 種別 | 料金(調査時点) | 無料お試し | 新規受付 |
|---|---|---|---|---|
エックスサーバー | 共有 | スタンダード36ヶ月契約で月額990円(税込)。2026年11月4日18時7分時点の通常料金 | 10日間 | 受付中。最大30%オフのキャンペーン(10月5日〜11月4日)は終了 |
さくらのレンタルサーバ | 共有 | スタンダード月額500円〜 | 2週間 | 受付中 |
mixhost | 共有 | ライト月額495円〜。キャンペーンではライト12ヶ月で初回月額594円(税込) | 記載なし | 受付中 |
シン・レンタルサーバー | 共有 | 2026年9月1日に値上げ。11月時点でキャンペーンなし | 10日間 | 受付中 |
ConoHa WING | 共有 | — | なし | 2026年10月24日から停止中(再開時期未定) |
ConoHa VPS | VPS | まとめトク36ヶ月で月額326円、1ヶ月単位なら月額460円、時間課金1.3円/時〜(最安は1コア・メモリ512MB・SSD30GB) | なし(時間課金に最低利用期間なし) | 10月23日に再開後、24日から再び停止 |
さくらのVPS | VPS | 2GBプラン月額1,594円〜 | 2週間 | 10月23日に石狩、10月30日に大阪の一部プランで再開 |
KAGOYA CLOUD VPS | VPS | 最安月額770円(2Core・2GB・NVMe200GB)。日額課金あり | なし(日額課金で試せる) | 10月27日に再開 |
XServer VPS | VPS | 9月1日に値上げ。4GBプランは1ヶ月契約で月額2,640円 | 無料VPSは7月10日から受付停止 | 9月17日から停止中。11月中に再開予定(確定ではない) |
お名前.com VPS | VPS | 2Core・1GB・SSD100GBで月額985円 | 記載なし | — |
表の数値は2026年11月時点の各社公開情報をまとめたものです。料金も受付状況も短期間で変わっています。申し込む直前に、各社の公式サイトで料金ページと「お知らせ」欄を必ず確認してください。長期契約の割引は初回だけで、更新時に高くなるケースもあります。初回価格と一緒に「更新後の月額」も見ておくと安心です。
以前は25番ポートで直接送信、今は587番+SMTP認証で書く
以前の書き方:localhostの25番ポートに投げる
VPSや自宅サーバーでは、以前はサーバー内にメール配送ソフト(MTA)を入れていました。Pythonからは localhost に送るだけ、という書き方がよく使われていました。
import smtplib
from email.mime.text import MIMEText
msg = MIMEText("本文", "plain", "utf-8")
msg["Subject"] = "日次レポート"
msg["From"] = "送信元アドレス"
msg["To"] = "送信先アドレス"
with smtplib.SMTP("localhost") as smtp: # 既定は25番ポート
smtp.sendmail(msg["From"], [msg["To"]], msg.as_string())この書き方は、サーバー内のMTAが25番ポートで相手のメールサーバーへ直接届けられる前提で成り立っています。自宅回線ではOP25Bに止められます。VPSでも25番ポートの扱いは事業者や契約によって異なります。さらに、自前のMTAから届けたメールは、送信ドメインの認証設定が揃っていないと迷惑メール扱いされやすくなります。「1日1通の通知」のために抱える手間としては重すぎます。
今の書き方:既存のメールアカウントのSMTPに587番で認証して渡す
今は、すでに持っているメールアカウントのSMTPサーバーを使います。587番ポート(メール投稿用のサブミッションポート)に接続し、STARTTLSで暗号化してからログインして送ります。宛先への配送はそのメールサーバーが担当するので、実行場所が自宅でもVPSでも同じコードで動きます。
import smtplib
import ssl
from email.message import EmailMessage
msg = EmailMessage()
msg["Subject"] = "日次レポート"
msg["From"] = "送信元アドレス"
msg["To"] = "送信先アドレス"
msg.set_content("本文")
context = ssl.create_default_context()
with smtplib.SMTP("smtp.example.com", 587, timeout=30) as smtp:
smtp.starttls(context=context)
smtp.login("username", "パスワード")
smtp.send_message(msg)以前の書き方からの変更点は3つです。
EmailMessageを使う:MIMETextを組み立てる代わりに、set_content()で本文を入れます。日本語の文字コードは自動で処理されます。EmailMessageはPython 3.6で標準ライブラリに追加されました。starttls()に検証つきのコンテキストを渡す:ssl.create_default_context()を使うと、サーバー証明書を検証したうえで暗号化します。send_message()で送る:ヘッダーの From/To から送信元と宛先を読み取ります。as_string()で文字列にする手順は不要です。
SMTPサーバー名・ポート・ユーザー名は、メールアカウントの「メールソフト設定」欄などに書かれている値を使います。レンタルサーバーの契約にメール機能があれば、サーバーパネルで確認できます。587番は外部への直接配送ではなく、自分のアカウントへの「投稿」です。OP25Bの対象外として扱われるのが一般的ですが、念のため次の確認スクリプトで実際に試してください。
契約したらまず確認:その環境から587番に出られるか
さくらのVPSやConoHa VPSの25番ポートの扱いについて、今回の調査では2026年11月時点の公式な制限内容を確認できませんでした。そのため具体的な条件は書きません。公式ドキュメントで確かめるのが前提ですが、もっと確実なのは実際に接続してみることです。さくらのVPSやエックスサーバーの無料お試し期間、あるいはConoHa VPSやKAGOYA CLOUD VPSの時間・日額課金を使えば、本契約の前に次のスクリプトを実行できます。
import socket
import sys
host = sys.argv[1] if len(sys.argv) > 1 else "smtp.example.com"
for port in (25, 587):
try:
with socket.create_connection((host, port), timeout=10) as sock:
banner = sock.recv(200).decode(errors="replace").strip()
print(f"{port}: 接続できた {banner}")
except OSError as e:
print(f"{port}: 接続できない {e}")このスクリプトは、自分が使うSMTPサーバーに25番と587番でつながるかを1回ずつ試すだけです。メールは送りません。python3 check_smtp.py smtp.example.com のように実行して、587番で 220 から始まる応答が返れば、送信経路は確保できています。25番が「接続できない」でも、587番が通れば問題ありません。
毎朝動かすPythonスクリプト一式(requests+EmailMessage)
実行環境
- Python 3(
EmailMessageを使うため3.6以上)。サーバー上でpython3 --versionを実行して確認します。 - 追加パッケージは
requestsだけです。メール送信・robots.txtの解釈・設定ファイルの読み込みは標準ライブラリで済みます。
python3 -m pip install --user requests
python3 -m pip show requests共有レンタルサーバーには root権限がありません。そのため --user をつけて自分のホームディレクトリにインストールします。今回の用途では特定バージョンへの固定は不要です。pip show で表示されたバージョンを控えておけば、後で挙動が変わったときの手がかりになります。
設定ファイル:パスワードをスクリプトに書かない
cronから起動したプログラムには、ログイン時に読み込まれる環境変数が渡らないことがあります。そこで認証情報は、本人だけが読める設定ファイルに分けておきます。
; /home/username/.config/daily_report.ini
[smtp]
host = smtp.example.com
port = 587
user = username
password = (メールアカウントのパスワード)
from_addr = (送信元のメールアドレス)
to_addr = (受け取りたいメールアドレス)chmod 600 /home/username/.config/daily_report.ini本体:取得してメールで送る
import configparser
import re
import smtplib
import ssl
import time
import urllib.robotparser
from datetime import datetime
from email.message import EmailMessage
from pathlib import Path
import requests
CONFIG_PATH = Path("/home/username/.config/daily_report.ini")
TARGET_URL = "https://example.com/news"
ROBOTS_URL = "https://example.com/robots.txt"
USER_AGENT = "daily-report-bot/1.0 (+https://example.com/)"
def load_config():
config = configparser.ConfigParser()
config.read(CONFIG_PATH, encoding="utf-8")
return config["smtp"]
def allowed_by_robots():
rp = urllib.robotparser.RobotFileParser()
rp.set_url(ROBOTS_URL)
rp.read()
return rp.can_fetch(USER_AGENT, TARGET_URL)
def fetch_summary():
res = requests.get(TARGET_URL, headers={"User-Agent": USER_AGENT}, timeout=30)
res.raise_for_status()
res.encoding = res.apparent_encoding
m = re.search(r"<title>(.*?)</title>", res.text, re.S)
title = m.group(1).strip() if m else "(titleなし)"
return f"ステータス: {res.status_code}\nページタイトル: {title}\nサイズ: {len(res.content)} bytes"
def send_mail(cfg, subject, body):
msg = EmailMessage()
msg["Subject"] = subject
msg["From"] = cfg["from_addr"]
msg["To"] = cfg["to_addr"]
msg.set_content(body)
context = ssl.create_default_context()
with smtplib.SMTP(cfg["host"], cfg.getint("port"), timeout=30) as smtp:
smtp.starttls(context=context)
smtp.login(cfg["user"], cfg["password"])
smtp.send_message(msg)
def main():
cfg = load_config()
started = time.monotonic()
today = datetime.now().strftime("%Y-%m-%d")
try:
if not allowed_by_robots():
subject = f"[日次] {today} 取得をスキップ"
body = "robots.txtで取得が許可されていないため、取得しませんでした。"
else:
subject = f"[日次] {today} 取得成功"
body = fetch_summary()
except Exception as e:
subject = f"[日次] {today} 取得失敗"
body = f"{type(e).__name__}: {e}"
elapsed = time.monotonic() - started
body += f"\n\n処理時間: {elapsed:.1f} 秒"
send_mail(cfg, subject, body)
if __name__ == "__main__":
main()ブロックごとの役割は次のとおりです。
- 定数:取得先のURL、robots.txtの場所、名乗るUser-Agentをまとめています。User-Agentに連絡先のURLを入れておくと、相手のサイト管理者が問い合わせ先を判断できます。
load_config():先ほどの設定ファイルから[smtp]セクションを読みます。スクリプト本体にはパスワードを持たせません。allowed_by_robots():標準ライブラリのurllib.robotparserでrobots.txtを読み、対象URLへのアクセスが許可されているかを判定します。fetch_summary():ページを1回だけ取得します。timeout=30は、相手が応答しないときに処理が止まらないようにするためです。raise_for_status()で4xx/5xxを例外にして、失敗メールの側に回します。中身の解析はここを書き換えて使ってください。send_mail():前の節で示した587番+STARTTLS+ログインの送り方です。main():取得に失敗しても例外を握りつぶさず、「取得失敗」の件名でメールを送ります。毎日動かすうえで大事なのは、「メールが来ない=止まっている」と判断できる状態にしておくことです。本文の最後には処理時間を入れています。この数値が自分の環境での実測値になり、日々のメールで推移を追えます。
取得先サイトへの配慮:robots.txt・利用規約・アクセス間隔
- robots.txt:上のコードのように毎回確認し、許可されていなければ取得しません。
- 利用規約:robots.txtで許可されていても、規約で自動取得を禁止しているサイトがあります。最初に一度読み、規約が変わっていないか定期的に見直してください。
- アクセス間隔:このスクリプトは1日1回、1ページ1リクエストです。複数ページを取る場合は、1件ごとに
time.sleep()で数秒以上空けてください。対象を必要なページだけに絞ることも大切です。並列でまとめて取りに行く書き方はしません。 - ログインや制限の回避はしない:会員限定ページ、アクセス制限、ボット対策がかかっているページは、自動取得の対象から外します。公式のAPIや配信(RSSなど)があるなら、そちらを使います。
cron登録と毎日動かし続ける条件:エックスサーバー・VPS・自宅PCが止まる場面
cronの書き方(共通)
0 7 * * * /usr/bin/python3 /home/username/scripts/daily_report.py >> /home/username/logs/daily_report.log 2>&10 7 * * *:毎日7時0分に実行します。/usr/bin/python3:cronではPATHがログイン時と違うことがあるため、Pythonはフルパスで書きます。実際のパスは、SSHでログインできる環境ならwhich python3で確認します。>> ... 2>&1:通常の出力もエラーもログファイルに追記します。メール自体が送れなかったときの手がかりになります。
エックスサーバーのような共有レンタルサーバーでは、サーバーパネルのcron設定画面に、上の「時刻」と「コマンド」を分けて入力します。最短実行間隔はサービスごとに決まっていますが、1日1回ならどのサービスでも問題になりません。
環境ごとの「止まる条件」と向いている人
環境 | 止まる条件 | 向いているケース |
|---|---|---|
手元のPC | 電源を切る、スリープに入る、OS更新後に再起動したまま、回線が落ちる | まず動作を試したい段階。毎日の運用には向かない |
共有レンタルサーバー(エックスサーバー等) | 実行時間やCPU使用量が上限を超えると強制終了される。常駐はできない | 処理が数分以内で終わる1日1回の通知。メール機能つきなら送信経路もそろう |
VPS(ConoHa VPS・さくらのVPS・KAGOYA等) | OSやセキュリティの更新を自分でしないと危険。事業者側のメンテナンスで止まることもある。25番ポートの扱いは契約前に確認 | 常駐が必要、処理が長い、Pythonのバージョンを自由に選びたい |
自宅サーバー | 停電、回線断、機器の故障。外出中は復旧できない | 家庭内の機器と連携したい処理。メールは587番+外部SMTPが前提 |
手元のPCで動かす場合は、Windows Updateの再起動でタスクが動かなかった日がないか確認しましょう。更新の確認方法は Windows 11 11月更新 確認方法|更新の履歴とOSビルド にまとめています。共有レンタルサーバーで処理が長くなってきた場合は、強制終了の条件と分割の書き方を レンタルサーバー cron 強制終了|30分バッチ 26年11月 で解説しています。
どこを選べば送信で詰まらないか
- 処理が短く、1日1回で足りる:共有レンタルサーバーで十分です。エックスサーバー(10日間無料)やさくらのレンタルサーバ(2週間無料)なら、お試し期間中にcron登録から587番での送信まで確認できます。
- 常駐や長時間の処理が必要:VPSを選びます。2026年11月時点で新規受付をしているのは、KAGOYA CLOUD VPS(10月27日再開)と、さくらのVPSの一部リージョン・プランです。ConoHa VPSとXServer VPSは新規受付を停止しています。契約できたら、まず確認スクリプトで587番を試してください。
- 自宅で動かしたい:25番ポートでの直接送信は使えない前提で、最初から587番+既存のメールアカウントで書きます。
関連する選択肢
毎日決まった時刻にスクリプトを動かすだけなら、共有のレンタルサーバーでも足ります。cronが使えるプランを選べば、自分でOSを管理する必要はありません。
※ 広告を含みます(A8.net)。リンク経由でお申し込みがあった場合、手数料を受け取ることがあります。
送信で詰まらない環境の結論:1日1回なら共有サーバーのcron+587番
毎朝の処理結果をメールで送るだけなら、常駐もroot権限も要りません。まずは共有レンタルサーバーのcronで十分です。エックスサーバーはスタンダード36ヶ月契約で月額990円(2026年11月4日時点)、さくらのレンタルサーバはスタンダード月額500円〜で、どちらも無料お試し期間があります。メールは、以前のようにlocalhostの25番ポートへ投げる書き方をやめましょう。EmailMessage を使い、既存アカウントのSMTPへ587番+STARTTLS+認証で渡せば、自宅でもVPSでも同じコードで動きます。VPSは10月のカーネル脆弱性対応で受付状況が変わり続けているので、契約前に公式の「お知らせ」を確認してください。契約したら、587番に接続できるかを最初に試しましょう。失敗時も必ずメールを送る作りにしておけば、届かない日に止まっていると気づけます。