diff --git a/app/mailers/emails/projects.rb b/app/mailers/emails/projects.rb
index 14c724b5b918b9726aba2b69787ff47f2d916757..35459cceead6190e422cc67581c15cf677424e18 100644
--- a/app/mailers/emails/projects.rb
+++ b/app/mailers/emails/projects.rb
@@ -68,6 +68,20 @@ def prometheus_alert_fired_email(project, user, alert)
       mail(to: user.notification_email_for(@project.group), subject: subject(subject_text))
     end
 
+    def inactive_project_deletion_warning_email(project, user, deletion_date)
+      @project = project
+      @user = user
+      @deletion_date = deletion_date
+      subject = "Action required: Project #{project.name} is scheduled to be deleted on " \
+      "#{deletion_date} due to inactivity"
+
+      mail(to: user.notification_email_for(project.group),
+           subject: subject(subject)) do |format|
+        format.html { render layout: 'mailer' }
+        format.text { render layout: 'mailer' }
+      end
+    end
+
     private
 
     def add_alert_headers
diff --git a/app/mailers/previews/notify_preview.rb b/app/mailers/previews/notify_preview.rb
index e7c8964a7334c08cd2b1887eb01bc1d866c08fe0..60d594651655d4ec41372a91f4994bb626bb9983 100644
--- a/app/mailers/previews/notify_preview.rb
+++ b/app/mailers/previews/notify_preview.rb
@@ -201,6 +201,10 @@ def merge_when_pipeline_succeeds_email
     Notify.merge_when_pipeline_succeeds_email(user.id, merge_request.id, user.id).message
   end
 
+  def inactive_project_deletion_warning
+    Notify.inactive_project_deletion_warning_email(project, user, '2022-04-22').message
+  end
+
   private
 
   def project
diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb
index 062841e3aa5da29cbe81b218b85d9d54a59118d1..5c874994d6ed12542d18e73b741ae9b424b141cd 100644
--- a/app/services/notification_service.rb
+++ b/app/services/notification_service.rb
@@ -769,6 +769,12 @@ def unapprove_mr(merge_request, current_user)
     unapprove_mr_email(merge_request, merge_request.target_project, current_user)
   end
 
+  def inactive_project_deletion_warning(project, deletion_date)
+    owners_and_maintainers_without_invites(project).to_a.each do |recipient|
+      mailer.inactive_project_deletion_warning_email(project, recipient.user, deletion_date).deliver_later
+    end
+  end
+
   protected
 
   def new_resource_email(target, current_user, method)
diff --git a/app/views/notify/inactive_project_deletion_warning_email.html.haml b/app/views/notify/inactive_project_deletion_warning_email.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..154bfbb90a4838c36146bb43739717cdc9287fd5
--- /dev/null
+++ b/app/views/notify/inactive_project_deletion_warning_email.html.haml
@@ -0,0 +1,28 @@
+- project_link = link_to(_("%{project_name}") % { project_name: @project.name }, @project.http_url_to_repo)
+- projects_api_link = link_to(_("Projects API"), help_page_url('api/projects'))
+- events_api_link = link_to(_("Events API"), help_page_url('api/events', anchor: 'list-a-projects-visible-events'))
+
+%p
+  = _('Hi %{username},') % { username: sanitize_name(@user.name) }
+
+%p
+  = html_escape(_("Due to inactivity, the %{project_link} project is scheduled to be deleted on %{deletion_date}. To unschedule the deletion of %{project_link}, perform some activity on it. For example:")) % { project_link: project_link.html_safe, deletion_date: @deletion_date }
+
+%p
+  %ul
+    %li= _("Create or close an issue.")
+    %li= _("Create, update, or delete a merge request.")
+    %li= _("Push code to the repository.")
+    %li= _("Add or remove a user.")
+
+%p
+  = html_escape(_("To ensure %{project_link} is unscheduled for deletion, check that activity has been logged by GitLab. For example:")) %{project_link: project_link.html_safe}
+
+%p
+  %ul
+    %li= html_escape(_("Go to the %{b_open}Activity%{b_close} page for %{project_link}.")) % { project_link: project_link, b_open: '<b>'.html_safe, b_close: '</b>'.html_safe }
+    %li= html_escape(_("View the %{code_open}last_activity_at%{code_close} attribute for %{project_link} using the %{projects_api_link}.")) % { project_link: project_link.html_safe, projects_api_link: projects_api_link.html_safe, code_open: '<code>'.html_safe, code_close: '</code>'.html_safe }
+    %li= html_escape(_("List the visible events for %{project_link} using the %{events_api_link}.")) % { project_link: project_link.html_safe, events_api_link: events_api_link.html_safe }
+
+%p
+  = html_escape(_("This email supersedes any previous emails about scheduled deletion you may have received for %{project_link}.")) % { project_link: project_link.html_safe }
diff --git a/app/views/notify/inactive_project_deletion_warning_email.text.erb b/app/views/notify/inactive_project_deletion_warning_email.text.erb
new file mode 100644
index 0000000000000000000000000000000000000000..a0b79967817494d5d2c72a745a1c4e1df508b802
--- /dev/null
+++ b/app/views/notify/inactive_project_deletion_warning_email.text.erb
@@ -0,0 +1,17 @@
+<%= _('Hi %{username},') % { username: sanitize_name(@user.name) } %>
+
+<%= _("Due to inactivity, the %{project_name} (%{project_link}) project is scheduled to be deleted on %{deletion_date}. To unschedule the deletion of %{project_name}, perform some activity on it. For example:") %
+      { project_name: @project.name, project_link: @project.http_url_to_repo, deletion_date: @deletion_date } %>
+
+<%= _("- Create or close an issue.") %>
+<%= _("- Create, update, or delete a merge request.") %>
+<%= _("- Push code to the repository.") %>
+<%= _("- Add or remove a user.") %>
+
+<%= _("To ensure %{project_name} is unscheduled for deletion, check that activity has been logged by GitLab. For example:") % { project_name: @project.name } %>
+
+<%= _("- Go to the Activity page for %{project_name}.") % { project_name: @project.name } %>
+<%= _("- View the last_activity_at attribute for %{project_name} using the Project API %{projects_api_link}.") % { project_name: @project.name, projects_api_link: help_page_url('api/projects') } %>
+<%= _("- List the visible events for %{project_name} using the Events API %{events_api_link}.") % { project_name: @project.name, events_api_link: help_page_url('api/events', anchor: 'list-a-projects-visible-events') } %>
+
+<%= _("This email supersedes any previous emails about scheduled deletion you may have received for %{project_name}.") % { project_name: @project.name } %>
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 0cdece3990da409e454b24576536f3b25ac1800d..3a80ede19e6fa9ca84077265093637f44f983aff 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -896,6 +896,9 @@ msgstr ""
 msgid "%{policy_link} (notifying after %{elapsed_time} minutes unless %{status})"
 msgstr ""
 
+msgid "%{project_name}"
+msgstr ""
+
 msgid "%{project_path} is a project that you can use to add a README to your GitLab profile. Create a public project and initialize the repository with a README to get started. %{help_link_start}Learn more.%{help_link_end}"
 msgstr ""
 
@@ -1290,17 +1293,35 @@ msgstr ""
 msgid "- %{policy_name} (notifying after %{elapsed_time} minutes unless %{status})"
 msgstr ""
 
+msgid "- Add or remove a user."
+msgstr ""
+
 msgid "- Available to run jobs."
 msgstr ""
 
+msgid "- Create or close an issue."
+msgstr ""
+
+msgid "- Create, update, or delete a merge request."
+msgstr ""
+
 msgid "- Event"
 msgid_plural "- Events"
 msgstr[0] ""
 msgstr[1] ""
 
+msgid "- Go to the Activity page for %{project_name}."
+msgstr ""
+
+msgid "- List the visible events for %{project_name} using the Events API %{events_api_link}."
+msgstr ""
+
 msgid "- Not available to run jobs."
 msgstr ""
 
+msgid "- Push code to the repository."
+msgstr ""
+
 msgid "- Select -"
 msgstr ""
 
@@ -1309,6 +1330,9 @@ msgid_plural "- Users"
 msgstr[0] ""
 msgstr[1] ""
 
+msgid "- View the last_activity_at attribute for %{project_name} using the Project API %{projects_api_link}."
+msgstr ""
+
 msgid "- of - issues closed"
 msgstr ""
 
@@ -2225,6 +2249,9 @@ msgstr ""
 msgid "Add new directory"
 msgstr ""
 
+msgid "Add or remove a user."
+msgstr ""
+
 msgid "Add or remove previously merged commits"
 msgstr ""
 
@@ -10419,6 +10446,9 @@ msgstr ""
 msgid "Create one"
 msgstr ""
 
+msgid "Create or close an issue."
+msgstr ""
+
 msgid "Create or import your first project"
 msgstr ""
 
@@ -10458,6 +10488,9 @@ msgstr ""
 msgid "Create your group"
 msgstr ""
 
+msgid "Create, update, or delete a merge request."
+msgstr ""
+
 msgid "Create/import your first project"
 msgstr ""
 
@@ -13326,6 +13359,12 @@ msgstr ""
 msgid "Due date"
 msgstr ""
 
+msgid "Due to inactivity, the %{project_link} project is scheduled to be deleted on %{deletion_date}. To unschedule the deletion of %{project_link}, perform some activity on it. For example:"
+msgstr ""
+
+msgid "Due to inactivity, the %{project_name} (%{project_link}) project is scheduled to be deleted on %{deletion_date}. To unschedule the deletion of %{project_name}, perform some activity on it. For example:"
+msgstr ""
+
 msgid "Duplicate page: %{error_message}"
 msgstr ""
 
@@ -14835,6 +14874,9 @@ msgstr ""
 msgid "Events"
 msgstr ""
 
+msgid "Events API"
+msgstr ""
+
 msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
 msgstr ""
 
@@ -17350,6 +17392,9 @@ msgstr ""
 msgid "Go to snippets"
 msgstr ""
 
+msgid "Go to the %{b_open}Activity%{b_close} page for %{project_link}."
+msgstr ""
+
 msgid "Go to the 'Admin area &gt; Sign-up restrictions', and check 'Allowed domains for sign-ups'."
 msgstr ""
 
@@ -18557,6 +18602,9 @@ msgstr ""
 msgid "Hi %{username}!"
 msgstr ""
 
+msgid "Hi %{username},"
+msgstr ""
+
 msgid "Hidden"
 msgstr ""
 
@@ -22746,6 +22794,9 @@ msgstr ""
 msgid "List the merge requests that must be merged before this one."
 msgstr ""
 
+msgid "List the visible events for %{project_link} using the %{events_api_link}."
+msgstr ""
+
 msgid "List view"
 msgstr ""
 
@@ -29900,6 +29951,9 @@ msgstr ""
 msgid "Projects (%{count})"
 msgstr ""
 
+msgid "Projects API"
+msgstr ""
+
 msgid "Projects Successfully Retrieved"
 msgstr ""
 
@@ -30623,6 +30677,9 @@ msgstr ""
 msgid "Push an existing folder"
 msgstr ""
 
+msgid "Push code to the repository."
+msgstr ""
+
 msgid "Push commits to the source branch or add previously merged commits to review them."
 msgstr ""
 
@@ -38359,6 +38416,12 @@ msgstr ""
 msgid "This domain is not verified. You will need to verify ownership before access is enabled."
 msgstr ""
 
+msgid "This email supersedes any previous emails about scheduled deletion you may have received for %{project_link}."
+msgstr ""
+
+msgid "This email supersedes any previous emails about scheduled deletion you may have received for %{project_name}."
+msgstr ""
+
 msgid "This endpoint has been requested too many times. Try again later."
 msgstr ""
 
@@ -39206,6 +39269,12 @@ msgstr ""
 msgid "To enable Registration Features, first enable Service Ping."
 msgstr ""
 
+msgid "To ensure %{project_link} is unscheduled for deletion, check that activity has been logged by GitLab. For example:"
+msgstr ""
+
+msgid "To ensure %{project_name} is unscheduled for deletion, check that activity has been logged by GitLab. For example:"
+msgstr ""
+
 msgid "To ensure no loss of personal content, this account should only be used for matters related to %{group_name}."
 msgstr ""
 
@@ -41486,6 +41555,9 @@ msgstr ""
 msgid "View supported languages and frameworks"
 msgstr ""
 
+msgid "View the %{code_open}last_activity_at%{code_close} attribute for %{project_link} using the %{projects_api_link}."
+msgstr ""
+
 msgid "View the documentation"
 msgstr ""
 
diff --git a/spec/mailers/emails/projects_spec.rb b/spec/mailers/emails/projects_spec.rb
index b9c71e35bc66e34e8f973a62df128e181fd0741c..ec8c8497081bbe9ea0b9f476b4addd4235555e62 100644
--- a/spec/mailers/emails/projects_spec.rb
+++ b/spec/mailers/emails/projects_spec.rb
@@ -180,4 +180,32 @@
       end
     end
   end
+
+  describe '.inactive_project_deletion_warning_email' do
+    let(:recipient) { user }
+    let(:deletion_date) { Date.current }
+
+    subject { Notify.inactive_project_deletion_warning_email(project, user, deletion_date) }
+
+    it_behaves_like 'an email sent to a user'
+    it_behaves_like 'an email sent from GitLab'
+    it_behaves_like 'it should not have Gmail Actions links'
+    it_behaves_like 'a user cannot unsubscribe through footer link'
+    it_behaves_like 'appearance header and footer enabled'
+    it_behaves_like 'appearance header and footer not enabled'
+
+    it 'has the correct subject and body' do
+      project_link = "<a href=\"#{project.http_url_to_repo}\">#{project.name}</a>"
+
+      is_expected.to have_subject("#{project.name} | Action required: Project #{project.name} is scheduled to be " \
+        "deleted on #{deletion_date} due to inactivity")
+      is_expected.to have_body_text(project.http_url_to_repo)
+      is_expected.to have_body_text("Due to inactivity, the #{project_link} project is scheduled to be deleted " \
+        "on #{deletion_date}")
+      is_expected.to have_body_text("To ensure #{project_link} is unscheduled for deletion, check that activity has " \
+        "been logged by GitLab")
+      is_expected.to have_body_text("This email supersedes any previous emails about scheduled deletion you may " \
+        "have received for #{project_link}.")
+    end
+  end
 end
diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb
index 956a95eafb7aa9c6488d1b19e982a8e44ef86b35..743a04eabe6cac1822ec93f9fb8500a0cbe7a13c 100644
--- a/spec/services/notification_service_spec.rb
+++ b/spec/services/notification_service_spec.rb
@@ -3708,6 +3708,26 @@ def create_pipeline(user, status)
     end
   end
 
+  describe '#inactive_project_deletion_warning' do
+    let_it_be(:deletion_date) { Date.current }
+    let_it_be(:project) { create(:project) }
+    let_it_be(:maintainer) { create(:user) }
+    let_it_be(:developer) { create(:user) }
+
+    before do
+      project.add_maintainer(maintainer)
+    end
+
+    subject { notification.inactive_project_deletion_warning(project, deletion_date) }
+
+    it "sends email to project owners and maintainers" do
+      expect { subject }.to have_enqueued_email(project, maintainer, deletion_date,
+                                                mail: "inactive_project_deletion_warning_email")
+      expect { subject }.not_to have_enqueued_email(project, developer, deletion_date,
+                                                    mail: "inactive_project_deletion_warning_email")
+    end
+  end
+
   def build_team(project)
     @u_watcher               = create_global_setting_for(create(:user), :watch)
     @u_participating         = create_global_setting_for(create(:user), :participating)