前言#
今日は自動打刻ツールを作成し、メールサービスを構築して打刻結果をフィードバックする準備をしています。使用するメールは Yandex メールです。エラー「SMTP ホストからの不正な挨拶: smtp.yandex.com, ポート: 465, 応答: [EOF]」が発生したので、記録しておきます。
メールの準備#
メールの使用に特別な要件はなく、SMTP をサポートしていれば問題ありません。
メールの登録#
メールのログイン#
メールにログインすると、SMTP を有効にするように求められる場合があります。
こちらは公式が提供する SMTP を有効にするためのドキュメントで、ポート番号も記載されています。
SMTP の有効化#
メールのホームページ右上の歯車 > セキュリティ > メールクライアント >
ここで Outlook を使用して接続をテストしました。使用したポートは 465 で、接続成功の画像を添付します。
メールプロトコル#
SMTP プロトコル#
SMTP は比較的シンプルなテキストベースのプロトコルです。その上で、メッセージの 1 つまたは複数の受信者(ほとんどの場合、存在が確認されている)を指定し、メッセージテキストが転送されます。telnet プログラムを使用して SMTP サーバーを簡単にテストできます。SSL 暗号化を提供する SMTP プロトコルは SMTPS と呼ばれ、SMTP は TCP ポート25
を使用し、SMTPS は TCP ポート465
を使用します。
POP3 プロトコル#
POP3 は「Post Office Protocol - Version 3」の略で、「郵便局プロトコルバージョン 3」です。これは TCP/IP プロトコルファミリーの一部で、RFC1939 で定義されています。このプロトコルは、クライアントがサーバー上の電子メールをリモートで管理することをサポートするために主に使用されます。SSL 暗号化を提供する POP3 プロトコルは POP3S と呼ばれ、POP3 のデフォルトポートは110
、POP3S のデフォルトポートは995
です。
IMAP プロトコル#
IMAP(Internet Mail Access Protocol)は以前はインタラクティブメールアクセスプロトコル(Interactive Mail Access Protocol)と呼ばれていたアプリケーション層プロトコルです。IMAP はスタンフォード大学が 1986 年に開発したメール取得プロトコルです。主な機能は、メールクライアントがこのプロトコルを使用してメールサーバーからメール情報を取得したり、メールをダウンロードしたりすることです。現在の権威ある定義は RFC3501 です。IMAP プロトコルは TCP/IP プロトコルの上で動作し、使用するポートは143
です。POP3 プロトコルとの主な違いは、ユーザーがすべてのメールをダウンロードする必要がなく、クライアントを介してサーバー上のメールを直接操作できることです。SSL 暗号化を提供する IMAP プロトコルは IMAP S と呼ばれ、POP3 のデフォルトポートは143
、POP3S のデフォルトポートは993
です。
構築手順と簡単な使用法#
mail 依存#
build.gradle ファイル
compile group: 'org.springframework.boot', name: 'spring-boot-starter-mail', version: '2.3.2.RELEASE'
yml 設定ファイル#
server:
port: 80
logging:
level:
web: debug
spring:
mail:
default-encoding: UTF-8
host: smtp.yandex.com
username: [email protected]
password: 123456
port: 25 #smtpプロトコルは25ポートを使用
# port: 465 #smtpsは465ポートを使用、さもなければエラーが発生します。
protocol: smtp #プロトコルを指定
test-connection: true
properties:
mail:
smtp:
auth: true # 使用
starttls: # SSLセキュリティプロトコルを使用するため、以下のように設定する必要があります
enable: true
required: true
java コード#
MailService インターフェースファイル#
public interface MailService {
/**
* プレーンテキストメールを送信
* @param toAddr 受信者
* @param title タイトル
* @param content 内容
*/
void sendTextMail(String toAddr, String title, String content);
/**
* HTMLメールを送信
* @param toAddr 受信者
* @param title タイトル
* @param content 内容(HTML)
*/
void sendHtmlMail(String toAddr, String title, String content);
/**
* 添付ファイル付きのメールを送信
* @param toAddr 受信者
* @param title タイトル
* @param content 内容
* @param filePath 添付ファイルのパス
*/
void sendAttachmentsMail(String toAddr, String title, String content, String filePath);
/**
* テキストに静的リソース(画像)が含まれるメールを送信
* @param toAddr 受信者
* @param title タイトル
* @param content 内容
* @param rscPath リソースパス
* @param rscId リソースID(複数の画像がある可能性があります)
*/
void sendInlineResourceMail(String toAddr, String title, String content, String rscPath, String rscId);
}
MailServiceImpl ファイル#
@Component
public class MailServiceImpl implements MailService {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private final JavaMailSender mailSender;
/**
* 定数を注入
*/
@Value("${spring.mail.username}")
private String from;
public MailServiceImpl(JavaMailSender mailSender) {
this.mailSender = mailSender;
}
/**
* プレーンテキストメールを送信
*
* @param toAddr 受信者
* @param title タイトル
* @param content 内容
*/
@Override
public void sendTextMail(String toAddr, String title, String content) {
// プレーンテキストメールオブジェクト
SimpleMailMessage message = new SimpleMailMessage();
message.setFrom(from);
message.setTo(toAddr);
message.setSubject(title);
message.setText(content);
try {
mailSender.send(message);
if (logger.isInfoEnabled()) {
logger.info("テキストメールが送信されました。");
}
} catch (Exception e) {
logger.error("テキストメール送信中に例外が発生しました!", e);
}
}
/**
* HTMLメールを送信
*
* @param toAddr 受信者
* @param title タイトル
* @param content 内容(HTML)
*/
@Override
public void sendHtmlMail(String toAddr, String title, String content) {
// HTMLメールオブジェクト
MimeMessage message = mailSender.createMimeMessage();
try {
// trueはマルチパートメッセージを作成する必要があることを示します
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setFrom(from);
helper.setTo(toAddr);
helper.setSubject(title);
helper.setText(content, true);
mailSender.send(message);
if (logger.isInfoEnabled()) {
logger.info("HTMLメールが送信されました");
}
} catch (MessagingException e) {
logger.error("HTMLメール送信中に例外が発生しました!", e);
}
}
/**
* 添付ファイル付きのメールを送信
*
* @param toAddr 受信者
* @param title タイトル
* @param content 内容
* @param filePath 添付ファイルのパス
*/
@Override
public void sendAttachmentsMail(String toAddr, String title, String content, String filePath) {
MimeMessage message = mailSender.createMimeMessage();
try {
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setFrom(from);
helper.setTo(toAddr);
helper.setSubject(title);
helper.setText(content, true);
FileSystemResource file = new FileSystemResource(new File(filePath));
String fileName = filePath.substring(filePath.lastIndexOf(File.separator));
helper.addAttachment(fileName, file);
mailSender.send(message);
if (logger.isInfoEnabled()) {
logger.info("添付ファイル付きのメールが送信されました。");
}
} catch (MessagingException e) {
logger.error("添付ファイル付きのメール送信中に例外が発生しました!", e);
}
}
/**
* テキストに静的リソース(画像)が含まれるメールを送信
*
* @param toAddr 受信者
* @param title タイトル
* @param content 内容
* @param rscPath リソースパス
* @param rscId リソースID(複数の画像がある可能性があります)
*/
@Override
public void sendInlineResourceMail(String toAddr, String title, String content, String rscPath, String rscId) {
MimeMessage message = mailSender.createMimeMessage();
try {
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setFrom(from);
helper.setTo(toAddr);
helper.setSubject(title);
helper.setText(content, true);
FileSystemResource res = new FileSystemResource(new File(rscPath));
helper.addInline(rscId, res);
mailSender.send(message);
if (logger.isInfoEnabled()) {
logger.info("静的リソースを埋め込んだメールが送信されました。");
}
} catch (MessagingException e) {
logger.error("静的リソースを埋め込んだメール送信中に例外が発生しました!", e);
}
}
}
テストクラス#
@SpringBootTest
class ClockInApplicationTests {
@Autowired
MailService mailService;
@Test
void sendTextMail(){
mailService.sendTextMail("[email protected]","単体テスト","テストメール送信");
}
}
実行結果#
タイトルに記載されているように、例外が発生しました
プロトコルに対応するポートを使用した後、送信に成功しました。画像を添付します。
結語#
この実践を通じて、コードを書く前に多くの準備が必要であること、あるいは私が理解していることが十分ではないことを感じました。エラーが発生した後、異常情報を百度で探しても見つからず、どこが間違っているのか考えました。以前 Outlook で接続テストが成功したので、コードの問題だと思いました。その後、多くの人が 25 ポートを使用して送信しているのを見て、ポートを百度で調べたところ、プロトコルとポートが一致していないことに気づきました。したがって、コードを書く前の準備が不十分または知識が不足していることが重要な情報を理解していないことにつながると思います。