운영중입니다

Postfix + PHPMailer로 동일한 메일 여러 사용자에게 발송하는 방법 본문

리눅스

Postfix + PHPMailer로 동일한 메일 여러 사용자에게 발송하는 방법

https443 2026. 5. 18. 23:23

웹 서버를 운영하다 보면
공지사항이나 보안 관련 안내 메일을 여러 사용자에게 안정적으로 발송해야 하는 경우가 많습니다.

이번 글에서는 Ubuntu 24.04 환경에서 Postfix와 PHPMailer를 이용하여 여러 사용자에게 
동일한 메일을 자동 발송하는 방법을 정리하였습니다.

특히 아래 사항들을 고려하여 실제 운영 환경 기준으로 구성하였습니다.

- 다수 사용자 개별 발송
- 중복 발송 방지
- 스팸 판정 완화
- 발송 기록 저장
- 재실행 방지(lock)
- PHP 기반 간단 구성


※ 본 글은 테스트 및 운영 경험을 기반으로 정리한 내용입니다.

 


1. Postfix, PHPMailer 란?

Postfix 는 리눅스 서버에서 사용하는 대표적인 메일 서버(MTA)입니다.
* Mail Transfer Agent (MTA)는 메일을 다른 서버로 전달하는 프로그램을 의미

  • 메일 발송
  • 메일 수신
  • 외부 메일 서버 전달

역할을 담당합니다. 즉, 서버에서 실제로 메일을 인터넷으로 보내주는 프로그램입니다.

Postfix 주요 특징

종류 메일 서버(MTA)
사용 환경 Ubuntu / CentOS
특징 빠름, 가벼움, 안정성
주요 역할 SMTP 메일 발송
사용 목적 시스템 메일, 웹메일, 공지 메일 발송

 

PHPMailer는 PHP에서 메일을 쉽게 발송할 수 있도록 도와주는 라이브러리입니다.

PHP 기본 mail 함수보다 훨씬 편리하며, 실무에서는 대부분 PHPMailer를 많이 사용합니다.

PHPMailer 주요 기능

기능지원 여부

 

HTML 메일 O
첨부파일 O
SMTP 인증 O
UTF-8 한글 처리 O
대량 메일 발송 O
오류 로그 확인 O

Postfix와 PHPMailer 차이

구분 역할
Postfix 실제 메일 서버
PHPMailer PHP 메일 발송 라이브러리

2. 테스트 환경

항목 내용
OS Ubuntu 24.04.2 LTS
PHP PHP 8.3
메일 발송 Postfix
메일 라이브러리 PHPMailer
작업 경로 /root/mailtest

   2.1 작업 디렉토리 생성

mkdir -p /root/mailtest
cd /root/mailtest


   2.2 필수 패키지 설치

apt install php-mbstring
#mbstring 확장이 없으면 한글 메일 처리 시 문제가 발생할 수 있다.

apt install postfix

Internet Site 선택

#System mail name:
#발송할 메일 주소를 입력하나 여기선 auto 로 설정하고 넘김

발송할 메일 주소를 입력해야하지만 여기선 auto 로 설정하여 사용함

     2.3 Postfix 서비스 확인

systemctl restart postfix
systemctl enable postfix
systemctl status postfix

 

    2.4 PHPMailer 최소 파일만 다운로드
* 전체 Git 저장소를 받을 필요 없이 필요한 파일만 받아도 동작한다.

cd /root/mailtest

mkdir -p PHPMailer/src

wget -O PHPMailer/src/PHPMailer.php \
https://raw.githubusercontent.com/PHPMailer/PHPMailer/master/src/PHPMailer.php

wget -O PHPMailer/src/SMTP.php \
https://raw.githubusercontent.com/PHPMailer/PHPMailer/master/src/SMTP.php

wget -O PHPMailer/src/Exception.php \
https://raw.githubusercontent.com/PHPMailer/PHPMailer/master/src/Exception.php

다운로드 후 아래 3개 파일이 존재하면 된다.

ls -al PHPMailer/src

#Exception.php
#PHPMailer.php
#SMTP.php


3. 사용

  3.1 수신 메일 목록 파일 생성

cat > maillist.txt << EOF
user1@example.com
user2@example.com
user3@example.com
EOF

# 위 내용은 테스트용이며 사용시에는 실제 메일을 기입


    3.2 메일 발송 PHP 코드 작성

<?php

use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;

require __DIR__ . '/PHPMailer/src/Exception.php';
require __DIR__ . '/PHPMailer/src/PHPMailer.php';
require __DIR__ . '/PHPMailer/src/SMTP.php';

date_default_timezone_set("Asia/Seoul");

/*
|--------------------------------------------------------------------------
| SMTP 설정
|--------------------------------------------------------------------------
*/

$smtpHost = "mail.example.com"; -> 사용 중인 메일서버
$smtpPort = 465; -> 포트
$smtpUser = "notice@example.com"; -> 사용자 계정
$smtpPass = "비밀번호"; -> 사용자 계정에 대한 비밀번호

/*
|--------------------------------------------------------------------------
| 발송 정보
|--------------------------------------------------------------------------
*/

$fromEmail = "notice@example.com"; -> 발송 주소
$fromName  = "이름"; -> 발송인
$subject   = "제목";

/*
|--------------------------------------------------------------------------
| 수신 목록
|--------------------------------------------------------------------------
*/

$mailListFile = __DIR__ . "/maillist.txt";
if (!file_exists($mailListFile)) {
    exit("maillist.txt 파일이 존재하지 않습니다.\n");
}
$recipients = file(
    $mailListFile,
    FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES
);
if (!$recipients || count($recipients) === 0) {
    exit("메일 주소가 없습니다.\n");
}

/*
|--------------------------------------------------------------------------
| 중복 실행 방지
|--------------------------------------------------------------------------
*/

$lockFile = __DIR__ . "/send_ssl_notice.lock";
$lockHandle = fopen($lockFile, "c");
if (!$lockHandle) {
    exit("잠금 파일 생성 실패\n");
}
if (!flock($lockHandle, LOCK_EX | LOCK_NB)) {
    exit("이미 실행 중입니다.\n");


/*
|--------------------------------------------------------------------------
| 발송 완료 기록
|--------------------------------------------------------------------------
*/

$sentFile = __DIR__ . "/send_ssl_notice_sent.json";
$sentList = [];
if (file_exists($sentFile)) {
    $json = file_get_contents($sentFile);
    $sentList = json_decode($json, true);
    if (!is_array($sentList)) {
        $sentList = [];
    }


/*
|--------------------------------------------------------------------------
| 메일 본문
|--------------------------------------------------------------------------
*/

$body = '
<html>
<head>
<meta charset="UTF-8">
</head>
<body style="
    font-family: Malgun Gothic, Apple SD Gothic Neo, sans-serif;
    font-size:14px;
    color:#111;
    line-height:1.8;
">
본문 작성
';


/*
|--------------------------------------------------------------------------
| 중복 제거
|--------------------------------------------------------------------------
*/

$recipients = array_unique($recipients);

/*
|--------------------------------------------------------------------------
| 개별 발송
|--------------------------------------------------------------------------
*/

foreach ($recipients as $to) {
    $to = trim($to);
    if (empty($to)) {
        continue;
    }
    if (!filter_var($to, FILTER_VALIDATE_EMAIL)) {
        echo "[SKIP] 잘못된 이메일 주소: {$to}\n";
        continue;
    }
    if (isset($sentList[$to])) {
        echo "[SKIP] 이미 발송 완료: {$to}\n";
        continue;
    }
    try {
        $mail = new PHPMailer(true);
        /*
        |--------------------------------------------------------------------------
        | SMTP 설정
        |--------------------------------------------------------------------------
        */
        $mail->isSMTP();
        $mail->Host       = $smtpHost;
        $mail->SMTPAuth   = true;
        $mail->Username   = $smtpUser;
        $mail->Password   = $smtpPass;
        $mail->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS;
        $mail->Port       = $smtpPort;
        /*
        |--------------------------------------------------------------------------
        | 메일 설정
        |--------------------------------------------------------------------------
        */
        $mail->CharSet = "UTF-8";
        $mail->setFrom($fromEmail, $fromName);
        $mail->addAddress($to);
        // 참조 추가
        $mail->addCC("참조 받을 주소");
        $mail->Subject = $subject;
        $mail->isHTML(true);
        $mail->Body = $body;
        $mail->AltBody = "안내 메일입니다.";
        /*
        |--------------------------------------------------------------------------
        | 발송
        |--------------------------------------------------------------------------
        */
        $mail->send();
        /*
        |--------------------------------------------------------------------------
        | 발송 완료 기록
        |--------------------------------------------------------------------------
        */
        $sentList[$to] = [
            "sent_at" => date("Y-m-d H:i:s"),
            "subject" => $subject
        ];
        file_put_contents(
            $sentFile,
            json_encode(
                $sentList,
                JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT
            ),
            LOCK_EX
        );
        echo "[OK] 발송 완료: {$to}\n";
    } catch (Exception $e) {
        echo "[FAIL] {$to}\n";
        echo $mail->ErrorInfo . "\n";
    }


    /*
    |--------------------------------------------------------------------------
    | 스팸 판정 완화
    |--------------------------------------------------------------------------
    */

    sleep(2);
}

/*
|--------------------------------------------------------------------------
| 잠금 해제
|--------------------------------------------------------------------------
*/

flock($lockHandle, LOCK_UN);

fclose($lockHandle);

echo "전체 작업 완료\n";


    3.3 실행

php send_ssl_notice.php

실행 후 디렉토리에 생성된 파일들

 

이후 발송 된 메일을 확인한다.


   4. 주의 사항
   
4.1 너무 빠른 발송은 스팸 판정을 받을 수 있음

sleep(2);

#위와 같이 발송 간 딜레이를 주는 것을 권장한다.

   4.2 이미 발송한 주소는 재발송되지 않음

#sent.json 파일 기준으로 이미 발송된 주소는 자동 제외된다.

#동일 주소로 다시 발송하려면:

rm -f sent.json

#이후 다시 실행하면 된다.


    4.3 참조(CC) 제거 방법

#아래 코드가 있는 경우:

$mail->addCC("admin@example.com");

#사용하지 않으려면 앞에 // 처리하면 된다.

// $mail->addCC("admin@example.com");

  5. 마무리

Postfix와 PHPMailer를 조합하면 Ubuntu 서버에서도 비교적 간단하게 다수 사용자 대상 메일 발송 환경을 구축할 수 있다.

특히 운영 환경에서는 아래 기능들이 매우 중요하다.

- 중복 발송 방지
- SMTP 인증
- HTML 메일 지원
- 발송 기록 저장
- 스팸 완화 딜레이

단순 테스트 수준이 아니라 실제 운영에서도 충분히 활용 가능한 방식이며,
안내 메일, 점검 공지, 서비스 정책 안내 등 다양한 용도로 응용 가능하다.