PDF添付送信　送信たくさん　セキュ強

<h3>前提条件</h3>
<ul>
<li>1️⃣ メールサーバーアカウント作成</li>
<li>2️⃣ ライブラリ インスト</li>
<li>3️⃣ コード実行、token.json先に作っとく</li>
</ul>


<br>
<h3>1️⃣ メールサーバーアカウント作成</h3>

https://www.mailjet.com


<br>
<h3>メール、改行送りたい</h3>

```ruby:インスト
body = """こんにちは、

こちらは長文のメールです。
改行を入れる場合は、以下のように書きます。

よろしくお願いします。
"""
```

<h3>メールの実行結果</h3>

![スクリーンショット 2025-02-19 23.19.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/628823/014e18d0-4920-4703-bfd0-6e00331ace1c.png)


<br>
<h3>2️⃣ ライブラリ インスト</h3>

```ruby:インスト
pip install mailjet-rest
```

<br>
<h3>コード解説</h3>

```ruby:qiita.rb
encode_pdf関数 :PDFをBase64に変える。
複数の受信者設定
受信者情報を recipients リストに追加。リスト全員に同じPDF送信。
メールの送信
mailjet.send.create(data=data)  : 送信時、送信者、受信者、件名、本文、添付ファイルの情報を設定します。
結果確認
result.status_code : 成功したか確認。
```

<br>
<h3></h3>

```ruby:manypdf.py
from mailjet_rest import Client
import base64

# Mailjet APIキー設定
api_key = 'Api key'  
api_secret = '秘密鍵key'  
mailjet = Client(auth=(api_key, api_secret), version='v3.1')

# PDFファイルをBase64にエンコードする関数
def encode_pdf(file_path):
    with open(file_path, "rb") as f:
        pdf_data = f.read()
    return base64.b64encode(pdf_data).decode('utf-8')

# メール送信関数
def send_email_with_pdfs():
    # 送信するPDFファイルをBase64にエンコード
    resume_base64 = encode_pdf('履歴書 hoge.pdf') 
    cv_base64 = encode_pdf('職務経歴書 hoge.pdf')  

    # 複数の受信者リスト
    recipients = [
        {'Email': '送りたいメアド', 'Name': ''},
        {'Email': '送りたいメアド', 'Name': ''},
        {'Email': '送りたいメアド', 'Name': ''}
    ]

    # メッセージリスト（受信者ごと）
    messages = []
    for recipient in recipients:
        message = {
            'From': {
                'Email': 'hoge@gmail.com',
                'Name': 'hoge'
            },
            'To': [recipient],  
            'Subject': '書類のご送付',
            'TextPart': """
                           メールアドレスを教えていただき、
                           ありがとうございます。
                           書類を送ります。""",
            'Attachments': [
                {
                    'ContentType': 'application/pdf',
                    'Filename': '履歴書 hoge.pdf',
                    'Base64Content': resume_base64
                },
                {
                    'ContentType': 'application/pdf',
                    'Filename': 'hoge 職務経歴書.pdf',
                    'Base64Content': cv_base64
                }
            ]
        }
        messages.append(message)

    # メール送信データ
    data = {'Messages': messages}

    # メール送信
    result = mailjet.send.create(data=data)

    # 結果表示
    if result.status_code == 200:
        print('成功！')
    else:
        print(f"送れてないよ")
# 実行
send_email_with_pdfs()
```

<br>
<h3>スクレイピング　禁止理由</h3>

```ruby:qiita.rb
利用規約に違反
サーバーに過剰な負荷
他の利用者が使いづらくなる

サイトがスクレイピング検出で、アクセス制限かかる

著作権や知的財産の保護
求人情報や会社情報は、知的財産。
情報を無断で収集・再利用は、著作権や法的権利を侵害
```

<br>
<h3>PDF自動送信 セキュリティが一番高いもの</h3>

```ruby:qiita.rb
一番 : OAth認証。
二番目 : メールサーバー(SendGridやmailjet)
一番セキュリティが低い : Googleのアプリキー

```

<br>
<h3>OAth API 無料利用枠の多さと、設定のしやすさおすすめ</h3>

```ruby:qiita.rb
GitHub:OAuth設定がちょー簡単、
初心者でも設定しやすい。
無料で利用できるAPIの制限も高、
```


<br>
<h3>APIでスクレイピング 種類</h3>

```ruby:qiita.rb
1. 求人情報API
求人情報を取得するために、
ウェブサイトが提供している公式APIを使う方法です。

Indeed API
Indeedは求人情報を提供している大手プラットフォームで、APIを使って求人情報を取得できます。APIの利用には、利用申請やAPIキーの取得が必要です。
Indeed API Documentation

Careerjet API
Careerjetも求人情報を提供するサービスで、APIを提供しています。これを使えば、複数の求人サイトから情報を集めて利用することができます。
Careerjet API Documentation

Adzuna API
Adzunaは求人情報を集めるためのサービスで、APIを提供しており、求人情報を簡単に取得できます。
Adzuna API Documentation

LinkedIn API

2. ScraperAPI
ウェブサイトのコンテンツをプログラムから簡単に取得。
リクエスト時にIPローテーションやCAPTCHAの回避を自動的に行ってくれる

3. BeautifulSoupやSeleniumを使ったスクレイピング。


4. Google Custom Search JSON API
Google使って情報検索。
```

<br>
<h3>メールで文字を取得し、文字を加工</h3>

```ruby:qiita.rb
pip install email
```

```ruby:qiita.rb
pip install email

import imaplib
import email
from email.header import decode_header

# GmailのIMAPサーバーに接続
def connect_to_gmail():
    # IMAPサーバーに接続
    mail = imaplib.IMAP4_SSL("imap.gmail.com")
    
    # Gmailにログイン（アプリケーション専用パスワードを使って）
    mail.login("your-email@gmail.com", "your-app-password")
    
    # 受信トレイを選択
    mail.select("inbox")
    
    return mail

# メールを取得する関数
def get_emails(mail):
    # 検索条件を指定してメールを取得
    status, messages = mail.search(None, 'ALL')  # 'ALL'で全てのメールを取得
    email_ids = messages[0].split()  # メールIDリスト
    
    # 最新のメールから順番に処理
    for email_id in email_ids[::-1]:  # 最新から処理
        _, msg_data = mail.fetch(email_id, "(RFC822)")  # メールのデータを取得
        
        for response_part in msg_data:
            if isinstance(response_part, tuple):
                msg = email.message_from_bytes(response_part[1])  # メールの本文を取得
                subject, encoding = decode_header(msg["Subject"])[0]  # 件名をデコード
                if isinstance(subject, bytes):
                    subject = subject.decode(encoding if encoding else "utf-8")
                print("Subject:", subject)

                # メールの本文を取り出す
                if msg.is_multipart():
                    # メールがマルチパートの場合（添付ファイルなど）
                    for part in msg.walk():
                        content_type = part.get_content_type()
                        content_disposition = str(part.get("Content-Disposition"))
                        
                        if content_type == "text/plain" and "attachment" not in content_disposition:
                            # 本文がテキストで、添付ファイルでない場合
                            body = part.get_payload(decode=True).decode()
                            print("Body:", body)
                else:
                    # 単一のテキストメールの場合
                    body = msg.get_payload(decode=True).decode()
                    print("Body:", body)

# Gmailからメールを取得
mail = connect_to_gmail()
get_emails(mail)

# 接続を終了
mail.logout()
```

<h3>コード解説</h3>

```ruby:qiita.rb
connect_to_gmail()関数:
GmailのIMAPサーバー（imap.gmail.com）に接続し、ログインします。アプリ専用のパスワードを使ってログインすることが重要です。
mail.select("inbox")で受信トレイを選択します。
get_emails()関数:
mail.search(None, 'ALL')で全てのメールを取得します。ここでは、ALLを指定していますが、条件を変更して未読メールや特定のラベルがついたメールだけを取得することもできます。
取得したメールIDをmail.fetch()で各メールの内容を取得し、email.message_from_bytes()を使ってメールを解析します。
メールの件名や本文を表示します。もしメールがマルチパート（複数の部分から成る）であれば、本文をテキストとして取得します。
decode_header():
メールの件名（Subject）は、エンコーディングされている場合があるので、decode_header()を使ってエンコーディングを適切にデコードします。
メールの本文取得:
メールの本文がプレーンテキスト（text/plain）の場合、get_payload()を使って本文を取り出します。
<li>
転職でもバイトでも、理不尽を起こすのは全部採用側の事情次第

モヤモヤするけど、今回の件で「面接前に募集状況を再確認するのが大事」って気づけたのは収穫。無駄足を防ぐためにも、次回からは応募の際に「面接時にまだ枠があるか」確認を、習慣にしたらいいよ
</li>
```