diff --git a/controllers/meeting.js b/controllers/meeting.js
index dd15563bc203552e30854d111a21f54a7b2abf10..41cb07c0d0ef74434913c1c773b81ec0a8b9ab10 100644
--- a/controllers/meeting.js
+++ b/controllers/meeting.js
@@ -8,11 +8,12 @@ const {
   getMeetingWithParticipantsById,
   getMeetingWithParticipantsAndSchedulesById,
   getNumOfParticipantsByMeetingId,
-  closeMeetingById,
+  setMeetingClosedAndSendVoteEndEmail,
 } = require('../services/meeting');
 const {
   createPasswordNotMatchedError,
   createPasswordIsNullError,
+  createMeetingIsAlreadyClosedError,
 } = require('../errors/meetingErrors');
 const MeetingResponse = require('../dto/response/meetingResponse');
 const MeetingWithParticipantsResponse = require('../dto/response/meetingWithParticipantsResponse');
@@ -84,7 +85,7 @@ exports.createMeeting = async (req, res, next) => {
     });
 
     schedule.scheduleJob(meeting.voteExpiresAt, async () => {
-      await closeMeetingById(meeting.id);
+      await setMeetingClosedAndSendVoteEndEmail(meeting.id);
     });
 
     return res.status(201).json(MeetingResponse.from(meeting));
@@ -163,6 +164,12 @@ exports.getTopThreeConfirmedTimes = async (req, res, next) => {
   }
 };
 
+function validateMeetingIsNotClosed(meeting) {
+  if (meeting.isClosed === true) {
+    throw createMeetingIsAlreadyClosedError();
+  }
+}
+
 exports.closeMeeting = async (req, res, next) => {
   try {
     // TODO: query 최적화 필요
@@ -173,8 +180,9 @@ exports.closeMeeting = async (req, res, next) => {
       req.body.adminPassword,
       meeting.adminPassword,
     );
+    validateMeetingIsNotClosed(meeting);
 
-    await closeMeetingById(meetingId);
+    await setMeetingClosedAndSendVoteEndEmail(meetingId);
 
     meeting = await getMeetingWithParticipantsById(meetingId);
     return res.json(MeetingResponse.from(meeting));
diff --git a/schedules/checkMeetings.js b/schedules/checkMeetings.js
index 96c089e177423df85ba9a9c3b802d84a72ebfc8f..f927a9d5bdbf4fb346296e5c7e9796f4bb4041a7 100644
--- a/schedules/checkMeetings.js
+++ b/schedules/checkMeetings.js
@@ -1,7 +1,7 @@
 const { scheduleJob } = require('node-schedule');
 const { Op } = require('sequelize');
 const { Meeting } = require('../models');
-const { closeMeetingById } = require('../services/meeting');
+const { setMeetingClosedAndSendVoteEndEmail } = require('../services/meeting');
 
 module.exports = async () => {
   console.log(
@@ -18,7 +18,7 @@ module.exports = async () => {
     });
     meetings.forEach((meeting) => {
       scheduleJob(meeting.voteExpiresAt, async () => {
-        await closeMeetingById(meeting.id);
+        await setMeetingClosedAndSendVoteEndEmail(meeting.id);
       });
     });
   } catch (error) {
diff --git a/services/meeting.js b/services/meeting.js
index 30f59716a98d764af4b335017c8b6f67a9ba3240..a7d0ba8ce8b60c95af98372c97bfbbd6e638ddc9 100644
--- a/services/meeting.js
+++ b/services/meeting.js
@@ -57,15 +57,12 @@ const getNumOfParticipantsByMeetingId = async (meetingId) =>
     },
   });
 
-function validateMeetingIsNotClosed(meeting) {
-  if (meeting.isClosed === true) {
-    throw createMeetingIsAlreadyClosedError();
-  }
-}
-
-const closeMeetingById = async (meetingId) => {
+const setMeetingClosedAndSendVoteEndEmail = async (meetingId) => {
   const meeting = await getMeetingWithParticipantsById(meetingId);
-  validateMeetingIsNotClosed(meeting);
+
+  if (meeting.isClosed) {
+    return;
+  }
 
   meeting.isClosed = true;
   await meeting.save();
@@ -83,5 +80,5 @@ module.exports = {
   getMeetingWithParticipantsById,
   getMeetingWithParticipantsAndSchedulesById,
   getNumOfParticipantsByMeetingId,
-  closeMeetingById,
+  setMeetingClosedAndSendVoteEndEmail,
 };