2026-03-29

Convert-Zo3ToMail.ps1

 <#

簡易MIMEメール展開スクリプト


cURLで送信したEMLファイルを展開する。

検証環境やクローズド環境で使用して下さい。


MIT License

Copyright (c) 2026  yoshio (zo3.org)

Permission is hereby granted, free of charge, to any person obtaining a copy

of this software and associated documentation files (the "Software"), to deal

in the Software without restriction...

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND...

#>



param(

    [string]$EmlFile,

    [string]$OutDir = ".\out"

)


$CRLF = "`r`n"


# 出力先

New-Item -ItemType Directory -Force -Path $OutDir | Out-Null


# 全文取得

$content = Get-Content -Raw -Path $EmlFile


# ヘッダとボディ分離

$parts = $content -split "$CRLF$CRLF", 2

$headers = $parts[0]

$body = $parts[1]


# boundary取得

$boundary = $null

if ( $headers -match 'boundary="([^"]+)"') {

    $boundary = $matches[1]

}


# RFC2231 decode

function Decode-RFC2231($s) {

    if ($s -match "UTF-8''(.+)") {

        $enc = $matches[1]

        $bytes = @()

        for ($i = 0; $i -lt $enc.Length; ) {

            if ($enc[$i] -eq '%') {

                $bytes += [Convert]::ToByte($enc.Substring($i + 1, 2), 16)

                $i += 3

            }

            else {

                $bytes += [byte][char]$enc[$i]

                $i++

            }

        }

        return [System.Text.Encoding]::UTF8.GetString($bytes)

    }

    return $s

}


# Base64 decode

function Decode-Base64($text) {

    $clean = ($text -replace '\s', '')

    return [Convert]::FromBase64String($clean)

}


if ( $null -eq $boundary ) {

    # 単一パート 本文のみ

    $textPath = Join-Path $OutDir "body.txt"

    Set-Content -Path $textPath -Value $body -Encoding UTF8

}

else {

    # マルチパート分解

    $sections = $body -split "--$boundary"


    foreach ($sec in $sections) {


        if ($sec -match "--\s*$") { continue }

        if ($sec.Trim() -eq "") { continue }


        $sp = $sec -split "$CRLF$CRLF", 2

        if ( $sp.Count -lt 2 ) { continue }


        $h = $sp[0]

        $b = $sp[1].Trim()


        # 添付判定

        if ( -not ( $h -match "Content-Disposition: attachment" ) ) {

            # 本文

            $textPath = Join-Path $OutDir "body.txt"

            Set-Content -Path $textPath -Value $b -Encoding UTF8

        }

        else {

            # filename取得(優先:filename*)

            $filename = "unknown.bin"


            if ($h -match "filename\*=(.+)") {

                $filename = Decode-RFC2231 $matches[1].Trim()

            }

            elseif ($h -match 'filename="([^"]+)"') {

                $filename = $matches[1]

            }


            # Base64デコード

            if ($h -match "base64") {

                $bytes = Decode-Base64 $b

                $outPath = Join-Path $OutDir $filename

                [System.IO.File]::WriteAllBytes($outPath, $bytes)

            }

        }

    }

}