| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | |
| 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| 21 | 22 | 23 | 24 | 25 | 26 | 27 |
| 28 | 29 | 30 |
- 서버관리
- sftp
- oops-firwall
- linux
- SSL인증서
- ip차단
- postfix
- FTP
- SMTP설정
- centos7
- DNS
- 국가IP차단
- geoip
- 서버운영
- iptables
- 파일질라
- https
- CentOS
- 서버방화벽
- ubuntu
- 리눅스
- FileZilla
- 웹서버
- 리눅스명령어
- 오블완
- 시스템관리
- 리눅스서버
- 티스토리챌린지
- 서버보안
- Apache
- Today
- Total
운영중입니다
Postfix + PHPMailer로 동일한 메일 여러 사용자에게 발송하는 방법 본문
웹 서버를 운영하다 보면
공지사항이나 보안 관련 안내 메일을 여러 사용자에게 안정적으로 발송해야 하는 경우가 많습니다.
이번 글에서는 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

#System mail name:
#발송할 메일 주소를 입력하나 여기선 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 메일 지원
- 발송 기록 저장
- 스팸 완화 딜레이
단순 테스트 수준이 아니라 실제 운영에서도 충분히 활용 가능한 방식이며,
안내 메일, 점검 공지, 서비스 정책 안내 등 다양한 용도로 응용 가능하다.
'리눅스' 카테고리의 다른 글
| Linux 서비스 자동실행(enable) 설정 방법 정리 (0) | 2026.05.17 |
|---|---|
| Apache ErrorLog /dev/null 설정 (0) | 2026.02.05 |
| Swap 메모리란 무엇인가? (0) | 2025.12.01 |
| Linux find 명령어 정리 및 활용 예시 2 (0) | 2025.11.22 |
| Linux find 명령어 정리 및 활용 예시 1 (0) | 2025.11.21 |