##// END OF EJS Templates
Replaced non standard Precedence email header with "X-Auto-Response-Suppress: OOF" (#9534)....
Jean-Philippe Lang -
r7685:f953426935e8
parent child
Show More
@@ -1,475 +1,475
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require 'ar_condition'
18 require 'ar_condition'
19
19
20 class Mailer < ActionMailer::Base
20 class Mailer < ActionMailer::Base
21 layout 'mailer'
21 layout 'mailer'
22 helper :application
22 helper :application
23 helper :issues
23 helper :issues
24 helper :custom_fields
24 helper :custom_fields
25
25
26 include ActionController::UrlWriter
26 include ActionController::UrlWriter
27 include Redmine::I18n
27 include Redmine::I18n
28
28
29 def self.default_url_options
29 def self.default_url_options
30 h = Setting.host_name
30 h = Setting.host_name
31 h = h.to_s.gsub(%r{\/.*$}, '') unless Redmine::Utils.relative_url_root.blank?
31 h = h.to_s.gsub(%r{\/.*$}, '') unless Redmine::Utils.relative_url_root.blank?
32 { :host => h, :protocol => Setting.protocol }
32 { :host => h, :protocol => Setting.protocol }
33 end
33 end
34
34
35 # Builds a tmail object used to email recipients of the added issue.
35 # Builds a tmail object used to email recipients of the added issue.
36 #
36 #
37 # Example:
37 # Example:
38 # issue_add(issue) => tmail object
38 # issue_add(issue) => tmail object
39 # Mailer.deliver_issue_add(issue) => sends an email to issue recipients
39 # Mailer.deliver_issue_add(issue) => sends an email to issue recipients
40 def issue_add(issue)
40 def issue_add(issue)
41 redmine_headers 'Project' => issue.project.identifier,
41 redmine_headers 'Project' => issue.project.identifier,
42 'Issue-Id' => issue.id,
42 'Issue-Id' => issue.id,
43 'Issue-Author' => issue.author.login
43 'Issue-Author' => issue.author.login
44 redmine_headers 'Issue-Assignee' => issue.assigned_to.login if issue.assigned_to
44 redmine_headers 'Issue-Assignee' => issue.assigned_to.login if issue.assigned_to
45 message_id issue
45 message_id issue
46 recipients issue.recipients
46 recipients issue.recipients
47 cc(issue.watcher_recipients - @recipients)
47 cc(issue.watcher_recipients - @recipients)
48 subject "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] (#{issue.status.name}) #{issue.subject}"
48 subject "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] (#{issue.status.name}) #{issue.subject}"
49 body :issue => issue,
49 body :issue => issue,
50 :issue_url => url_for(:controller => 'issues', :action => 'show', :id => issue)
50 :issue_url => url_for(:controller => 'issues', :action => 'show', :id => issue)
51 render_multipart('issue_add', body)
51 render_multipart('issue_add', body)
52 end
52 end
53
53
54 # Builds a tmail object used to email recipients of the edited issue.
54 # Builds a tmail object used to email recipients of the edited issue.
55 #
55 #
56 # Example:
56 # Example:
57 # issue_edit(journal) => tmail object
57 # issue_edit(journal) => tmail object
58 # Mailer.deliver_issue_edit(journal) => sends an email to issue recipients
58 # Mailer.deliver_issue_edit(journal) => sends an email to issue recipients
59 def issue_edit(journal)
59 def issue_edit(journal)
60 issue = journal.journalized.reload
60 issue = journal.journalized.reload
61 redmine_headers 'Project' => issue.project.identifier,
61 redmine_headers 'Project' => issue.project.identifier,
62 'Issue-Id' => issue.id,
62 'Issue-Id' => issue.id,
63 'Issue-Author' => issue.author.login
63 'Issue-Author' => issue.author.login
64 redmine_headers 'Issue-Assignee' => issue.assigned_to.login if issue.assigned_to
64 redmine_headers 'Issue-Assignee' => issue.assigned_to.login if issue.assigned_to
65 message_id journal
65 message_id journal
66 references issue
66 references issue
67 @author = journal.user
67 @author = journal.user
68 recipients issue.recipients
68 recipients issue.recipients
69 # Watchers in cc
69 # Watchers in cc
70 cc(issue.watcher_recipients - @recipients)
70 cc(issue.watcher_recipients - @recipients)
71 s = "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] "
71 s = "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] "
72 s << "(#{issue.status.name}) " if journal.new_value_for('status_id')
72 s << "(#{issue.status.name}) " if journal.new_value_for('status_id')
73 s << issue.subject
73 s << issue.subject
74 subject s
74 subject s
75 body :issue => issue,
75 body :issue => issue,
76 :journal => journal,
76 :journal => journal,
77 :issue_url => url_for(:controller => 'issues', :action => 'show', :id => issue)
77 :issue_url => url_for(:controller => 'issues', :action => 'show', :id => issue)
78
78
79 render_multipart('issue_edit', body)
79 render_multipart('issue_edit', body)
80 end
80 end
81
81
82 def reminder(user, issues, days)
82 def reminder(user, issues, days)
83 set_language_if_valid user.language
83 set_language_if_valid user.language
84 recipients user.mail
84 recipients user.mail
85 subject l(:mail_subject_reminder, :count => issues.size, :days => days)
85 subject l(:mail_subject_reminder, :count => issues.size, :days => days)
86 body :issues => issues,
86 body :issues => issues,
87 :days => days,
87 :days => days,
88 :issues_url => url_for(:controller => 'issues', :action => 'index',
88 :issues_url => url_for(:controller => 'issues', :action => 'index',
89 :set_filter => 1, :assigned_to_id => user.id,
89 :set_filter => 1, :assigned_to_id => user.id,
90 :sort => 'due_date:asc')
90 :sort => 'due_date:asc')
91 render_multipart('reminder', body)
91 render_multipart('reminder', body)
92 end
92 end
93
93
94 # Builds a tmail object used to email users belonging to the added document's project.
94 # Builds a tmail object used to email users belonging to the added document's project.
95 #
95 #
96 # Example:
96 # Example:
97 # document_added(document) => tmail object
97 # document_added(document) => tmail object
98 # Mailer.deliver_document_added(document) => sends an email to the document's project recipients
98 # Mailer.deliver_document_added(document) => sends an email to the document's project recipients
99 def document_added(document)
99 def document_added(document)
100 redmine_headers 'Project' => document.project.identifier
100 redmine_headers 'Project' => document.project.identifier
101 recipients document.recipients
101 recipients document.recipients
102 subject "[#{document.project.name}] #{l(:label_document_new)}: #{document.title}"
102 subject "[#{document.project.name}] #{l(:label_document_new)}: #{document.title}"
103 body :document => document,
103 body :document => document,
104 :document_url => url_for(:controller => 'documents', :action => 'show', :id => document)
104 :document_url => url_for(:controller => 'documents', :action => 'show', :id => document)
105 render_multipart('document_added', body)
105 render_multipart('document_added', body)
106 end
106 end
107
107
108 # Builds a tmail object used to email recipients of a project when an attachements are added.
108 # Builds a tmail object used to email recipients of a project when an attachements are added.
109 #
109 #
110 # Example:
110 # Example:
111 # attachments_added(attachments) => tmail object
111 # attachments_added(attachments) => tmail object
112 # Mailer.deliver_attachments_added(attachments) => sends an email to the project's recipients
112 # Mailer.deliver_attachments_added(attachments) => sends an email to the project's recipients
113 def attachments_added(attachments)
113 def attachments_added(attachments)
114 container = attachments.first.container
114 container = attachments.first.container
115 added_to = ''
115 added_to = ''
116 added_to_url = ''
116 added_to_url = ''
117 case container.class.name
117 case container.class.name
118 when 'Project'
118 when 'Project'
119 added_to_url = url_for(:controller => 'files', :action => 'index', :project_id => container)
119 added_to_url = url_for(:controller => 'files', :action => 'index', :project_id => container)
120 added_to = "#{l(:label_project)}: #{container}"
120 added_to = "#{l(:label_project)}: #{container}"
121 recipients container.project.notified_users.select {|user| user.allowed_to?(:view_files, container.project)}.collect {|u| u.mail}
121 recipients container.project.notified_users.select {|user| user.allowed_to?(:view_files, container.project)}.collect {|u| u.mail}
122 when 'Version'
122 when 'Version'
123 added_to_url = url_for(:controller => 'files', :action => 'index', :project_id => container.project)
123 added_to_url = url_for(:controller => 'files', :action => 'index', :project_id => container.project)
124 added_to = "#{l(:label_version)}: #{container.name}"
124 added_to = "#{l(:label_version)}: #{container.name}"
125 recipients container.project.notified_users.select {|user| user.allowed_to?(:view_files, container.project)}.collect {|u| u.mail}
125 recipients container.project.notified_users.select {|user| user.allowed_to?(:view_files, container.project)}.collect {|u| u.mail}
126 when 'Document'
126 when 'Document'
127 added_to_url = url_for(:controller => 'documents', :action => 'show', :id => container.id)
127 added_to_url = url_for(:controller => 'documents', :action => 'show', :id => container.id)
128 added_to = "#{l(:label_document)}: #{container.title}"
128 added_to = "#{l(:label_document)}: #{container.title}"
129 recipients container.recipients
129 recipients container.recipients
130 end
130 end
131 redmine_headers 'Project' => container.project.identifier
131 redmine_headers 'Project' => container.project.identifier
132 subject "[#{container.project.name}] #{l(:label_attachment_new)}"
132 subject "[#{container.project.name}] #{l(:label_attachment_new)}"
133 body :attachments => attachments,
133 body :attachments => attachments,
134 :added_to => added_to,
134 :added_to => added_to,
135 :added_to_url => added_to_url
135 :added_to_url => added_to_url
136 render_multipart('attachments_added', body)
136 render_multipart('attachments_added', body)
137 end
137 end
138
138
139 # Builds a tmail object used to email recipients of a news' project when a news item is added.
139 # Builds a tmail object used to email recipients of a news' project when a news item is added.
140 #
140 #
141 # Example:
141 # Example:
142 # news_added(news) => tmail object
142 # news_added(news) => tmail object
143 # Mailer.deliver_news_added(news) => sends an email to the news' project recipients
143 # Mailer.deliver_news_added(news) => sends an email to the news' project recipients
144 def news_added(news)
144 def news_added(news)
145 redmine_headers 'Project' => news.project.identifier
145 redmine_headers 'Project' => news.project.identifier
146 message_id news
146 message_id news
147 recipients news.recipients
147 recipients news.recipients
148 subject "[#{news.project.name}] #{l(:label_news)}: #{news.title}"
148 subject "[#{news.project.name}] #{l(:label_news)}: #{news.title}"
149 body :news => news,
149 body :news => news,
150 :news_url => url_for(:controller => 'news', :action => 'show', :id => news)
150 :news_url => url_for(:controller => 'news', :action => 'show', :id => news)
151 render_multipart('news_added', body)
151 render_multipart('news_added', body)
152 end
152 end
153
153
154 # Builds a tmail object used to email recipients of a news' project when a news comment is added.
154 # Builds a tmail object used to email recipients of a news' project when a news comment is added.
155 #
155 #
156 # Example:
156 # Example:
157 # news_comment_added(comment) => tmail object
157 # news_comment_added(comment) => tmail object
158 # Mailer.news_comment_added(comment) => sends an email to the news' project recipients
158 # Mailer.news_comment_added(comment) => sends an email to the news' project recipients
159 def news_comment_added(comment)
159 def news_comment_added(comment)
160 news = comment.commented
160 news = comment.commented
161 redmine_headers 'Project' => news.project.identifier
161 redmine_headers 'Project' => news.project.identifier
162 message_id comment
162 message_id comment
163 recipients news.recipients
163 recipients news.recipients
164 cc news.watcher_recipients
164 cc news.watcher_recipients
165 subject "Re: [#{news.project.name}] #{l(:label_news)}: #{news.title}"
165 subject "Re: [#{news.project.name}] #{l(:label_news)}: #{news.title}"
166 body :news => news,
166 body :news => news,
167 :comment => comment,
167 :comment => comment,
168 :news_url => url_for(:controller => 'news', :action => 'show', :id => news)
168 :news_url => url_for(:controller => 'news', :action => 'show', :id => news)
169 render_multipart('news_comment_added', body)
169 render_multipart('news_comment_added', body)
170 end
170 end
171
171
172 # Builds a tmail object used to email the recipients of the specified message that was posted.
172 # Builds a tmail object used to email the recipients of the specified message that was posted.
173 #
173 #
174 # Example:
174 # Example:
175 # message_posted(message) => tmail object
175 # message_posted(message) => tmail object
176 # Mailer.deliver_message_posted(message) => sends an email to the recipients
176 # Mailer.deliver_message_posted(message) => sends an email to the recipients
177 def message_posted(message)
177 def message_posted(message)
178 redmine_headers 'Project' => message.project.identifier,
178 redmine_headers 'Project' => message.project.identifier,
179 'Topic-Id' => (message.parent_id || message.id)
179 'Topic-Id' => (message.parent_id || message.id)
180 message_id message
180 message_id message
181 references message.parent unless message.parent.nil?
181 references message.parent unless message.parent.nil?
182 recipients(message.recipients)
182 recipients(message.recipients)
183 cc((message.root.watcher_recipients + message.board.watcher_recipients).uniq - @recipients)
183 cc((message.root.watcher_recipients + message.board.watcher_recipients).uniq - @recipients)
184 subject "[#{message.board.project.name} - #{message.board.name} - msg#{message.root.id}] #{message.subject}"
184 subject "[#{message.board.project.name} - #{message.board.name} - msg#{message.root.id}] #{message.subject}"
185 body :message => message,
185 body :message => message,
186 :message_url => url_for(message.event_url)
186 :message_url => url_for(message.event_url)
187 render_multipart('message_posted', body)
187 render_multipart('message_posted', body)
188 end
188 end
189
189
190 # Builds a tmail object used to email the recipients of a project of the specified wiki content was added.
190 # Builds a tmail object used to email the recipients of a project of the specified wiki content was added.
191 #
191 #
192 # Example:
192 # Example:
193 # wiki_content_added(wiki_content) => tmail object
193 # wiki_content_added(wiki_content) => tmail object
194 # Mailer.deliver_wiki_content_added(wiki_content) => sends an email to the project's recipients
194 # Mailer.deliver_wiki_content_added(wiki_content) => sends an email to the project's recipients
195 def wiki_content_added(wiki_content)
195 def wiki_content_added(wiki_content)
196 redmine_headers 'Project' => wiki_content.project.identifier,
196 redmine_headers 'Project' => wiki_content.project.identifier,
197 'Wiki-Page-Id' => wiki_content.page.id
197 'Wiki-Page-Id' => wiki_content.page.id
198 message_id wiki_content
198 message_id wiki_content
199 recipients wiki_content.recipients
199 recipients wiki_content.recipients
200 cc(wiki_content.page.wiki.watcher_recipients - recipients)
200 cc(wiki_content.page.wiki.watcher_recipients - recipients)
201 subject "[#{wiki_content.project.name}] #{l(:mail_subject_wiki_content_added, :id => wiki_content.page.pretty_title)}"
201 subject "[#{wiki_content.project.name}] #{l(:mail_subject_wiki_content_added, :id => wiki_content.page.pretty_title)}"
202 body :wiki_content => wiki_content,
202 body :wiki_content => wiki_content,
203 :wiki_content_url => url_for(:controller => 'wiki', :action => 'show',
203 :wiki_content_url => url_for(:controller => 'wiki', :action => 'show',
204 :project_id => wiki_content.project,
204 :project_id => wiki_content.project,
205 :id => wiki_content.page.title)
205 :id => wiki_content.page.title)
206 render_multipart('wiki_content_added', body)
206 render_multipart('wiki_content_added', body)
207 end
207 end
208
208
209 # Builds a tmail object used to email the recipients of a project of the specified wiki content was updated.
209 # Builds a tmail object used to email the recipients of a project of the specified wiki content was updated.
210 #
210 #
211 # Example:
211 # Example:
212 # wiki_content_updated(wiki_content) => tmail object
212 # wiki_content_updated(wiki_content) => tmail object
213 # Mailer.deliver_wiki_content_updated(wiki_content) => sends an email to the project's recipients
213 # Mailer.deliver_wiki_content_updated(wiki_content) => sends an email to the project's recipients
214 def wiki_content_updated(wiki_content)
214 def wiki_content_updated(wiki_content)
215 redmine_headers 'Project' => wiki_content.project.identifier,
215 redmine_headers 'Project' => wiki_content.project.identifier,
216 'Wiki-Page-Id' => wiki_content.page.id
216 'Wiki-Page-Id' => wiki_content.page.id
217 message_id wiki_content
217 message_id wiki_content
218 recipients wiki_content.recipients
218 recipients wiki_content.recipients
219 cc(wiki_content.page.wiki.watcher_recipients + wiki_content.page.watcher_recipients - recipients)
219 cc(wiki_content.page.wiki.watcher_recipients + wiki_content.page.watcher_recipients - recipients)
220 subject "[#{wiki_content.project.name}] #{l(:mail_subject_wiki_content_updated, :id => wiki_content.page.pretty_title)}"
220 subject "[#{wiki_content.project.name}] #{l(:mail_subject_wiki_content_updated, :id => wiki_content.page.pretty_title)}"
221 body :wiki_content => wiki_content,
221 body :wiki_content => wiki_content,
222 :wiki_content_url => url_for(:controller => 'wiki', :action => 'show',
222 :wiki_content_url => url_for(:controller => 'wiki', :action => 'show',
223 :project_id => wiki_content.project,
223 :project_id => wiki_content.project,
224 :id => wiki_content.page.title),
224 :id => wiki_content.page.title),
225 :wiki_diff_url => url_for(:controller => 'wiki', :action => 'diff',
225 :wiki_diff_url => url_for(:controller => 'wiki', :action => 'diff',
226 :project_id => wiki_content.project, :id => wiki_content.page.title,
226 :project_id => wiki_content.project, :id => wiki_content.page.title,
227 :version => wiki_content.version)
227 :version => wiki_content.version)
228 render_multipart('wiki_content_updated', body)
228 render_multipart('wiki_content_updated', body)
229 end
229 end
230
230
231 # Builds a tmail object used to email the specified user their account information.
231 # Builds a tmail object used to email the specified user their account information.
232 #
232 #
233 # Example:
233 # Example:
234 # account_information(user, password) => tmail object
234 # account_information(user, password) => tmail object
235 # Mailer.deliver_account_information(user, password) => sends account information to the user
235 # Mailer.deliver_account_information(user, password) => sends account information to the user
236 def account_information(user, password)
236 def account_information(user, password)
237 set_language_if_valid user.language
237 set_language_if_valid user.language
238 recipients user.mail
238 recipients user.mail
239 subject l(:mail_subject_register, Setting.app_title)
239 subject l(:mail_subject_register, Setting.app_title)
240 body :user => user,
240 body :user => user,
241 :password => password,
241 :password => password,
242 :login_url => url_for(:controller => 'account', :action => 'login')
242 :login_url => url_for(:controller => 'account', :action => 'login')
243 render_multipart('account_information', body)
243 render_multipart('account_information', body)
244 end
244 end
245
245
246 # Builds a tmail object used to email all active administrators of an account activation request.
246 # Builds a tmail object used to email all active administrators of an account activation request.
247 #
247 #
248 # Example:
248 # Example:
249 # account_activation_request(user) => tmail object
249 # account_activation_request(user) => tmail object
250 # Mailer.deliver_account_activation_request(user)=> sends an email to all active administrators
250 # Mailer.deliver_account_activation_request(user)=> sends an email to all active administrators
251 def account_activation_request(user)
251 def account_activation_request(user)
252 # Send the email to all active administrators
252 # Send the email to all active administrators
253 recipients User.active.find(:all, :conditions => {:admin => true}).collect { |u| u.mail }.compact
253 recipients User.active.find(:all, :conditions => {:admin => true}).collect { |u| u.mail }.compact
254 subject l(:mail_subject_account_activation_request, Setting.app_title)
254 subject l(:mail_subject_account_activation_request, Setting.app_title)
255 body :user => user,
255 body :user => user,
256 :url => url_for(:controller => 'users', :action => 'index',
256 :url => url_for(:controller => 'users', :action => 'index',
257 :status => User::STATUS_REGISTERED,
257 :status => User::STATUS_REGISTERED,
258 :sort_key => 'created_on', :sort_order => 'desc')
258 :sort_key => 'created_on', :sort_order => 'desc')
259 render_multipart('account_activation_request', body)
259 render_multipart('account_activation_request', body)
260 end
260 end
261
261
262 # Builds a tmail object used to email the specified user that their account was activated by an administrator.
262 # Builds a tmail object used to email the specified user that their account was activated by an administrator.
263 #
263 #
264 # Example:
264 # Example:
265 # account_activated(user) => tmail object
265 # account_activated(user) => tmail object
266 # Mailer.deliver_account_activated(user) => sends an email to the registered user
266 # Mailer.deliver_account_activated(user) => sends an email to the registered user
267 def account_activated(user)
267 def account_activated(user)
268 set_language_if_valid user.language
268 set_language_if_valid user.language
269 recipients user.mail
269 recipients user.mail
270 subject l(:mail_subject_register, Setting.app_title)
270 subject l(:mail_subject_register, Setting.app_title)
271 body :user => user,
271 body :user => user,
272 :login_url => url_for(:controller => 'account', :action => 'login')
272 :login_url => url_for(:controller => 'account', :action => 'login')
273 render_multipart('account_activated', body)
273 render_multipart('account_activated', body)
274 end
274 end
275
275
276 def lost_password(token)
276 def lost_password(token)
277 set_language_if_valid(token.user.language)
277 set_language_if_valid(token.user.language)
278 recipients token.user.mail
278 recipients token.user.mail
279 subject l(:mail_subject_lost_password, Setting.app_title)
279 subject l(:mail_subject_lost_password, Setting.app_title)
280 body :token => token,
280 body :token => token,
281 :url => url_for(:controller => 'account', :action => 'lost_password', :token => token.value)
281 :url => url_for(:controller => 'account', :action => 'lost_password', :token => token.value)
282 render_multipart('lost_password', body)
282 render_multipart('lost_password', body)
283 end
283 end
284
284
285 def register(token)
285 def register(token)
286 set_language_if_valid(token.user.language)
286 set_language_if_valid(token.user.language)
287 recipients token.user.mail
287 recipients token.user.mail
288 subject l(:mail_subject_register, Setting.app_title)
288 subject l(:mail_subject_register, Setting.app_title)
289 body :token => token,
289 body :token => token,
290 :url => url_for(:controller => 'account', :action => 'activate', :token => token.value)
290 :url => url_for(:controller => 'account', :action => 'activate', :token => token.value)
291 render_multipart('register', body)
291 render_multipart('register', body)
292 end
292 end
293
293
294 def test(user)
294 def test(user)
295 set_language_if_valid(user.language)
295 set_language_if_valid(user.language)
296 recipients user.mail
296 recipients user.mail
297 subject 'Redmine test'
297 subject 'Redmine test'
298 body :url => url_for(:controller => 'welcome')
298 body :url => url_for(:controller => 'welcome')
299 render_multipart('test', body)
299 render_multipart('test', body)
300 end
300 end
301
301
302 # Overrides default deliver! method to prevent from sending an email
302 # Overrides default deliver! method to prevent from sending an email
303 # with no recipient, cc or bcc
303 # with no recipient, cc or bcc
304 def deliver!(mail = @mail)
304 def deliver!(mail = @mail)
305 set_language_if_valid @initial_language
305 set_language_if_valid @initial_language
306 return false if (recipients.nil? || recipients.empty?) &&
306 return false if (recipients.nil? || recipients.empty?) &&
307 (cc.nil? || cc.empty?) &&
307 (cc.nil? || cc.empty?) &&
308 (bcc.nil? || bcc.empty?)
308 (bcc.nil? || bcc.empty?)
309
309
310 # Set Message-Id and References
310 # Set Message-Id and References
311 if @message_id_object
311 if @message_id_object
312 mail.message_id = self.class.message_id_for(@message_id_object)
312 mail.message_id = self.class.message_id_for(@message_id_object)
313 end
313 end
314 if @references_objects
314 if @references_objects
315 mail.references = @references_objects.collect {|o| self.class.message_id_for(o)}
315 mail.references = @references_objects.collect {|o| self.class.message_id_for(o)}
316 end
316 end
317
317
318 # Log errors when raise_delivery_errors is set to false, Rails does not
318 # Log errors when raise_delivery_errors is set to false, Rails does not
319 raise_errors = self.class.raise_delivery_errors
319 raise_errors = self.class.raise_delivery_errors
320 self.class.raise_delivery_errors = true
320 self.class.raise_delivery_errors = true
321 begin
321 begin
322 return super(mail)
322 return super(mail)
323 rescue Exception => e
323 rescue Exception => e
324 if raise_errors
324 if raise_errors
325 raise e
325 raise e
326 elsif mylogger
326 elsif mylogger
327 mylogger.error "The following error occured while sending email notification: \"#{e.message}\". Check your configuration in config/configuration.yml."
327 mylogger.error "The following error occured while sending email notification: \"#{e.message}\". Check your configuration in config/configuration.yml."
328 end
328 end
329 ensure
329 ensure
330 self.class.raise_delivery_errors = raise_errors
330 self.class.raise_delivery_errors = raise_errors
331 end
331 end
332 end
332 end
333
333
334 # Sends reminders to issue assignees
334 # Sends reminders to issue assignees
335 # Available options:
335 # Available options:
336 # * :days => how many days in the future to remind about (defaults to 7)
336 # * :days => how many days in the future to remind about (defaults to 7)
337 # * :tracker => id of tracker for filtering issues (defaults to all trackers)
337 # * :tracker => id of tracker for filtering issues (defaults to all trackers)
338 # * :project => id or identifier of project to process (defaults to all projects)
338 # * :project => id or identifier of project to process (defaults to all projects)
339 # * :users => array of user ids who should be reminded
339 # * :users => array of user ids who should be reminded
340 def self.reminders(options={})
340 def self.reminders(options={})
341 days = options[:days] || 7
341 days = options[:days] || 7
342 project = options[:project] ? Project.find(options[:project]) : nil
342 project = options[:project] ? Project.find(options[:project]) : nil
343 tracker = options[:tracker] ? Tracker.find(options[:tracker]) : nil
343 tracker = options[:tracker] ? Tracker.find(options[:tracker]) : nil
344 user_ids = options[:users]
344 user_ids = options[:users]
345
345
346 s = ARCondition.new ["#{IssueStatus.table_name}.is_closed = ? AND #{Issue.table_name}.due_date <= ?", false, days.day.from_now.to_date]
346 s = ARCondition.new ["#{IssueStatus.table_name}.is_closed = ? AND #{Issue.table_name}.due_date <= ?", false, days.day.from_now.to_date]
347 s << "#{Issue.table_name}.assigned_to_id IS NOT NULL"
347 s << "#{Issue.table_name}.assigned_to_id IS NOT NULL"
348 s << ["#{Issue.table_name}.assigned_to_id IN (?)", user_ids] if user_ids.present?
348 s << ["#{Issue.table_name}.assigned_to_id IN (?)", user_ids] if user_ids.present?
349 s << "#{Project.table_name}.status = #{Project::STATUS_ACTIVE}"
349 s << "#{Project.table_name}.status = #{Project::STATUS_ACTIVE}"
350 s << "#{Issue.table_name}.project_id = #{project.id}" if project
350 s << "#{Issue.table_name}.project_id = #{project.id}" if project
351 s << "#{Issue.table_name}.tracker_id = #{tracker.id}" if tracker
351 s << "#{Issue.table_name}.tracker_id = #{tracker.id}" if tracker
352
352
353 issues_by_assignee = Issue.find(:all, :include => [:status, :assigned_to, :project, :tracker],
353 issues_by_assignee = Issue.find(:all, :include => [:status, :assigned_to, :project, :tracker],
354 :conditions => s.conditions
354 :conditions => s.conditions
355 ).group_by(&:assigned_to)
355 ).group_by(&:assigned_to)
356 issues_by_assignee.each do |assignee, issues|
356 issues_by_assignee.each do |assignee, issues|
357 deliver_reminder(assignee, issues, days) if assignee && assignee.active?
357 deliver_reminder(assignee, issues, days) if assignee && assignee.active?
358 end
358 end
359 end
359 end
360
360
361 # Activates/desactivates email deliveries during +block+
361 # Activates/desactivates email deliveries during +block+
362 def self.with_deliveries(enabled = true, &block)
362 def self.with_deliveries(enabled = true, &block)
363 was_enabled = ActionMailer::Base.perform_deliveries
363 was_enabled = ActionMailer::Base.perform_deliveries
364 ActionMailer::Base.perform_deliveries = !!enabled
364 ActionMailer::Base.perform_deliveries = !!enabled
365 yield
365 yield
366 ensure
366 ensure
367 ActionMailer::Base.perform_deliveries = was_enabled
367 ActionMailer::Base.perform_deliveries = was_enabled
368 end
368 end
369
369
370 private
370 private
371 def initialize_defaults(method_name)
371 def initialize_defaults(method_name)
372 super
372 super
373 @initial_language = current_language
373 @initial_language = current_language
374 set_language_if_valid Setting.default_language
374 set_language_if_valid Setting.default_language
375 from Setting.mail_from
375 from Setting.mail_from
376
376
377 # Common headers
377 # Common headers
378 headers 'X-Mailer' => 'Redmine',
378 headers 'X-Mailer' => 'Redmine',
379 'X-Redmine-Host' => Setting.host_name,
379 'X-Redmine-Host' => Setting.host_name,
380 'X-Redmine-Site' => Setting.app_title,
380 'X-Redmine-Site' => Setting.app_title,
381 'Precedence' => 'bulk',
381 'X-Auto-Response-Suppress' => 'OOF',
382 'Auto-Submitted' => 'auto-generated'
382 'Auto-Submitted' => 'auto-generated'
383 end
383 end
384
384
385 # Appends a Redmine header field (name is prepended with 'X-Redmine-')
385 # Appends a Redmine header field (name is prepended with 'X-Redmine-')
386 def redmine_headers(h)
386 def redmine_headers(h)
387 h.each { |k,v| headers["X-Redmine-#{k}"] = v }
387 h.each { |k,v| headers["X-Redmine-#{k}"] = v }
388 end
388 end
389
389
390 # Overrides the create_mail method
390 # Overrides the create_mail method
391 def create_mail
391 def create_mail
392 # Removes the current user from the recipients and cc
392 # Removes the current user from the recipients and cc
393 # if he doesn't want to receive notifications about what he does
393 # if he doesn't want to receive notifications about what he does
394 @author ||= User.current
394 @author ||= User.current
395 if @author.pref[:no_self_notified]
395 if @author.pref[:no_self_notified]
396 recipients.delete(@author.mail) if recipients
396 recipients.delete(@author.mail) if recipients
397 cc.delete(@author.mail) if cc
397 cc.delete(@author.mail) if cc
398 end
398 end
399
399
400 notified_users = [recipients, cc].flatten.compact.uniq
400 notified_users = [recipients, cc].flatten.compact.uniq
401 # Rails would log recipients only, not cc and bcc
401 # Rails would log recipients only, not cc and bcc
402 mylogger.info "Sending email notification to: #{notified_users.join(', ')}" if mylogger
402 mylogger.info "Sending email notification to: #{notified_users.join(', ')}" if mylogger
403
403
404 # Blind carbon copy recipients
404 # Blind carbon copy recipients
405 if Setting.bcc_recipients?
405 if Setting.bcc_recipients?
406 bcc(notified_users)
406 bcc(notified_users)
407 recipients []
407 recipients []
408 cc []
408 cc []
409 end
409 end
410 super
410 super
411 end
411 end
412
412
413 # Rails 2.3 has problems rendering implicit multipart messages with
413 # Rails 2.3 has problems rendering implicit multipart messages with
414 # layouts so this method will wrap an multipart messages with
414 # layouts so this method will wrap an multipart messages with
415 # explicit parts.
415 # explicit parts.
416 #
416 #
417 # https://rails.lighthouseapp.com/projects/8994/tickets/2338-actionmailer-mailer-views-and-content-type
417 # https://rails.lighthouseapp.com/projects/8994/tickets/2338-actionmailer-mailer-views-and-content-type
418 # https://rails.lighthouseapp.com/projects/8994/tickets/1799-actionmailer-doesnt-set-template_format-when-rendering-layouts
418 # https://rails.lighthouseapp.com/projects/8994/tickets/1799-actionmailer-doesnt-set-template_format-when-rendering-layouts
419
419
420 def render_multipart(method_name, body)
420 def render_multipart(method_name, body)
421 if Setting.plain_text_mail?
421 if Setting.plain_text_mail?
422 content_type "text/plain"
422 content_type "text/plain"
423 body render(:file => "#{method_name}.text.erb",
423 body render(:file => "#{method_name}.text.erb",
424 :body => body,
424 :body => body,
425 :layout => 'mailer.text.erb')
425 :layout => 'mailer.text.erb')
426 else
426 else
427 content_type "multipart/alternative"
427 content_type "multipart/alternative"
428 part :content_type => "text/plain",
428 part :content_type => "text/plain",
429 :body => render(:file => "#{method_name}.text.erb",
429 :body => render(:file => "#{method_name}.text.erb",
430 :body => body, :layout => 'mailer.text.erb')
430 :body => body, :layout => 'mailer.text.erb')
431 part :content_type => "text/html",
431 part :content_type => "text/html",
432 :body => render_message("#{method_name}.html.erb", body)
432 :body => render_message("#{method_name}.html.erb", body)
433 end
433 end
434 end
434 end
435
435
436 # Makes partial rendering work with Rails 1.2 (retro-compatibility)
436 # Makes partial rendering work with Rails 1.2 (retro-compatibility)
437 def self.controller_path
437 def self.controller_path
438 ''
438 ''
439 end unless respond_to?('controller_path')
439 end unless respond_to?('controller_path')
440
440
441 # Returns a predictable Message-Id for the given object
441 # Returns a predictable Message-Id for the given object
442 def self.message_id_for(object)
442 def self.message_id_for(object)
443 # id + timestamp should reduce the odds of a collision
443 # id + timestamp should reduce the odds of a collision
444 # as far as we don't send multiple emails for the same object
444 # as far as we don't send multiple emails for the same object
445 timestamp = object.send(object.respond_to?(:created_on) ? :created_on : :updated_on)
445 timestamp = object.send(object.respond_to?(:created_on) ? :created_on : :updated_on)
446 hash = "redmine.#{object.class.name.demodulize.underscore}-#{object.id}.#{timestamp.strftime("%Y%m%d%H%M%S")}"
446 hash = "redmine.#{object.class.name.demodulize.underscore}-#{object.id}.#{timestamp.strftime("%Y%m%d%H%M%S")}"
447 host = Setting.mail_from.to_s.gsub(%r{^.*@}, '')
447 host = Setting.mail_from.to_s.gsub(%r{^.*@}, '')
448 host = "#{::Socket.gethostname}.redmine" if host.empty?
448 host = "#{::Socket.gethostname}.redmine" if host.empty?
449 "<#{hash}@#{host}>"
449 "<#{hash}@#{host}>"
450 end
450 end
451
451
452 private
452 private
453
453
454 def message_id(object)
454 def message_id(object)
455 @message_id_object = object
455 @message_id_object = object
456 end
456 end
457
457
458 def references(object)
458 def references(object)
459 @references_objects ||= []
459 @references_objects ||= []
460 @references_objects << object
460 @references_objects << object
461 end
461 end
462
462
463 def mylogger
463 def mylogger
464 Rails.logger
464 Rails.logger
465 end
465 end
466 end
466 end
467
467
468 # Patch TMail so that message_id is not overwritten
468 # Patch TMail so that message_id is not overwritten
469 module TMail
469 module TMail
470 class Mail
470 class Mail
471 def add_message_id( fqdn = nil )
471 def add_message_id( fqdn = nil )
472 self.message_id ||= ::TMail::new_message_id(fqdn)
472 self.message_id ||= ::TMail::new_message_id(fqdn)
473 end
473 end
474 end
474 end
475 end
475 end
@@ -1,479 +1,479
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class MailerTest < ActiveSupport::TestCase
20 class MailerTest < ActiveSupport::TestCase
21 include Redmine::I18n
21 include Redmine::I18n
22 include ActionController::Assertions::SelectorAssertions
22 include ActionController::Assertions::SelectorAssertions
23 fixtures :projects, :enabled_modules, :issues, :users, :members,
23 fixtures :projects, :enabled_modules, :issues, :users, :members,
24 :member_roles, :roles, :documents, :attachments, :news,
24 :member_roles, :roles, :documents, :attachments, :news,
25 :tokens, :journals, :journal_details, :changesets, :trackers,
25 :tokens, :journals, :journal_details, :changesets, :trackers,
26 :issue_statuses, :enumerations, :messages, :boards, :repositories,
26 :issue_statuses, :enumerations, :messages, :boards, :repositories,
27 :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions,
27 :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions,
28 :versions,
28 :versions,
29 :comments
29 :comments
30
30
31 def setup
31 def setup
32 ActionMailer::Base.deliveries.clear
32 ActionMailer::Base.deliveries.clear
33 Setting.host_name = 'mydomain.foo'
33 Setting.host_name = 'mydomain.foo'
34 Setting.protocol = 'http'
34 Setting.protocol = 'http'
35 Setting.plain_text_mail = '0'
35 Setting.plain_text_mail = '0'
36 end
36 end
37
37
38 def test_generated_links_in_emails
38 def test_generated_links_in_emails
39 Setting.host_name = 'mydomain.foo'
39 Setting.host_name = 'mydomain.foo'
40 Setting.protocol = 'https'
40 Setting.protocol = 'https'
41
41
42 journal = Journal.find(2)
42 journal = Journal.find(2)
43 assert Mailer.deliver_issue_edit(journal)
43 assert Mailer.deliver_issue_edit(journal)
44
44
45 mail = ActionMailer::Base.deliveries.last
45 mail = ActionMailer::Base.deliveries.last
46 assert_kind_of TMail::Mail, mail
46 assert_kind_of TMail::Mail, mail
47
47
48 assert_select_email do
48 assert_select_email do
49 # link to the main ticket
49 # link to the main ticket
50 assert_select "a[href=?]",
50 assert_select "a[href=?]",
51 "https://mydomain.foo/issues/1",
51 "https://mydomain.foo/issues/1",
52 :text => "Bug #1: Can't print recipes"
52 :text => "Bug #1: Can't print recipes"
53 # link to a referenced ticket
53 # link to a referenced ticket
54 assert_select "a[href=?][title=?]",
54 assert_select "a[href=?][title=?]",
55 "https://mydomain.foo/issues/2",
55 "https://mydomain.foo/issues/2",
56 "Add ingredients categories (Assigned)",
56 "Add ingredients categories (Assigned)",
57 :text => "#2"
57 :text => "#2"
58 # link to a changeset
58 # link to a changeset
59 assert_select "a[href=?][title=?]",
59 assert_select "a[href=?][title=?]",
60 "https://mydomain.foo/projects/ecookbook/repository/revisions/2",
60 "https://mydomain.foo/projects/ecookbook/repository/revisions/2",
61 "This commit fixes #1, #2 and references #1 &amp; #3",
61 "This commit fixes #1, #2 and references #1 &amp; #3",
62 :text => "r2"
62 :text => "r2"
63 end
63 end
64 end
64 end
65
65
66 def test_generated_links_with_prefix
66 def test_generated_links_with_prefix
67 relative_url_root = Redmine::Utils.relative_url_root
67 relative_url_root = Redmine::Utils.relative_url_root
68 Setting.host_name = 'mydomain.foo/rdm'
68 Setting.host_name = 'mydomain.foo/rdm'
69 Setting.protocol = 'http'
69 Setting.protocol = 'http'
70 Redmine::Utils.relative_url_root = '/rdm'
70 Redmine::Utils.relative_url_root = '/rdm'
71
71
72 journal = Journal.find(2)
72 journal = Journal.find(2)
73 assert Mailer.deliver_issue_edit(journal)
73 assert Mailer.deliver_issue_edit(journal)
74
74
75 mail = ActionMailer::Base.deliveries.last
75 mail = ActionMailer::Base.deliveries.last
76 assert_kind_of TMail::Mail, mail
76 assert_kind_of TMail::Mail, mail
77
77
78 assert_select_email do
78 assert_select_email do
79 # link to the main ticket
79 # link to the main ticket
80 assert_select "a[href=?]",
80 assert_select "a[href=?]",
81 "http://mydomain.foo/rdm/issues/1",
81 "http://mydomain.foo/rdm/issues/1",
82 :text => "Bug #1: Can't print recipes"
82 :text => "Bug #1: Can't print recipes"
83 # link to a referenced ticket
83 # link to a referenced ticket
84 assert_select "a[href=?][title=?]",
84 assert_select "a[href=?][title=?]",
85 "http://mydomain.foo/rdm/issues/2",
85 "http://mydomain.foo/rdm/issues/2",
86 "Add ingredients categories (Assigned)",
86 "Add ingredients categories (Assigned)",
87 :text => "#2"
87 :text => "#2"
88 # link to a changeset
88 # link to a changeset
89 assert_select "a[href=?][title=?]",
89 assert_select "a[href=?][title=?]",
90 "http://mydomain.foo/rdm/projects/ecookbook/repository/revisions/2",
90 "http://mydomain.foo/rdm/projects/ecookbook/repository/revisions/2",
91 "This commit fixes #1, #2 and references #1 &amp; #3",
91 "This commit fixes #1, #2 and references #1 &amp; #3",
92 :text => "r2"
92 :text => "r2"
93 end
93 end
94 ensure
94 ensure
95 # restore it
95 # restore it
96 Redmine::Utils.relative_url_root = relative_url_root
96 Redmine::Utils.relative_url_root = relative_url_root
97 end
97 end
98
98
99 def test_generated_links_with_prefix_and_no_relative_url_root
99 def test_generated_links_with_prefix_and_no_relative_url_root
100 relative_url_root = Redmine::Utils.relative_url_root
100 relative_url_root = Redmine::Utils.relative_url_root
101 Setting.host_name = 'mydomain.foo/rdm'
101 Setting.host_name = 'mydomain.foo/rdm'
102 Setting.protocol = 'http'
102 Setting.protocol = 'http'
103 Redmine::Utils.relative_url_root = nil
103 Redmine::Utils.relative_url_root = nil
104
104
105 journal = Journal.find(2)
105 journal = Journal.find(2)
106 assert Mailer.deliver_issue_edit(journal)
106 assert Mailer.deliver_issue_edit(journal)
107
107
108 mail = ActionMailer::Base.deliveries.last
108 mail = ActionMailer::Base.deliveries.last
109 assert_kind_of TMail::Mail, mail
109 assert_kind_of TMail::Mail, mail
110
110
111 assert_select_email do
111 assert_select_email do
112 # link to the main ticket
112 # link to the main ticket
113 assert_select "a[href=?]",
113 assert_select "a[href=?]",
114 "http://mydomain.foo/rdm/issues/1",
114 "http://mydomain.foo/rdm/issues/1",
115 :text => "Bug #1: Can't print recipes"
115 :text => "Bug #1: Can't print recipes"
116 # link to a referenced ticket
116 # link to a referenced ticket
117 assert_select "a[href=?][title=?]",
117 assert_select "a[href=?][title=?]",
118 "http://mydomain.foo/rdm/issues/2",
118 "http://mydomain.foo/rdm/issues/2",
119 "Add ingredients categories (Assigned)",
119 "Add ingredients categories (Assigned)",
120 :text => "#2"
120 :text => "#2"
121 # link to a changeset
121 # link to a changeset
122 assert_select "a[href=?][title=?]",
122 assert_select "a[href=?][title=?]",
123 "http://mydomain.foo/rdm/projects/ecookbook/repository/revisions/2",
123 "http://mydomain.foo/rdm/projects/ecookbook/repository/revisions/2",
124 "This commit fixes #1, #2 and references #1 &amp; #3",
124 "This commit fixes #1, #2 and references #1 &amp; #3",
125 :text => "r2"
125 :text => "r2"
126 end
126 end
127 ensure
127 ensure
128 # restore it
128 # restore it
129 Redmine::Utils.relative_url_root = relative_url_root
129 Redmine::Utils.relative_url_root = relative_url_root
130 end
130 end
131
131
132 def test_email_headers
132 def test_email_headers
133 issue = Issue.find(1)
133 issue = Issue.find(1)
134 Mailer.deliver_issue_add(issue)
134 Mailer.deliver_issue_add(issue)
135 mail = ActionMailer::Base.deliveries.last
135 mail = ActionMailer::Base.deliveries.last
136 assert_not_nil mail
136 assert_not_nil mail
137 assert_equal 'bulk', mail.header_string('Precedence')
137 assert_equal 'OOF', mail.header_string('X-Auto-Response-Suppress')
138 assert_equal 'auto-generated', mail.header_string('Auto-Submitted')
138 assert_equal 'auto-generated', mail.header_string('Auto-Submitted')
139 end
139 end
140
140
141 def test_plain_text_mail
141 def test_plain_text_mail
142 Setting.plain_text_mail = 1
142 Setting.plain_text_mail = 1
143 journal = Journal.find(2)
143 journal = Journal.find(2)
144 Mailer.deliver_issue_edit(journal)
144 Mailer.deliver_issue_edit(journal)
145 mail = ActionMailer::Base.deliveries.last
145 mail = ActionMailer::Base.deliveries.last
146 assert_equal "text/plain", mail.content_type
146 assert_equal "text/plain", mail.content_type
147 assert_equal 0, mail.parts.size
147 assert_equal 0, mail.parts.size
148 assert !mail.encoded.include?('href')
148 assert !mail.encoded.include?('href')
149 end
149 end
150
150
151 def test_html_mail
151 def test_html_mail
152 Setting.plain_text_mail = 0
152 Setting.plain_text_mail = 0
153 journal = Journal.find(2)
153 journal = Journal.find(2)
154 Mailer.deliver_issue_edit(journal)
154 Mailer.deliver_issue_edit(journal)
155 mail = ActionMailer::Base.deliveries.last
155 mail = ActionMailer::Base.deliveries.last
156 assert_equal 2, mail.parts.size
156 assert_equal 2, mail.parts.size
157 assert mail.encoded.include?('href')
157 assert mail.encoded.include?('href')
158 end
158 end
159
159
160 def test_mail_from_with_phrase
160 def test_mail_from_with_phrase
161 with_settings :mail_from => 'Redmine app <redmine@example.net>' do
161 with_settings :mail_from => 'Redmine app <redmine@example.net>' do
162 Mailer.deliver_test(User.find(1))
162 Mailer.deliver_test(User.find(1))
163 end
163 end
164 mail = ActionMailer::Base.deliveries.last
164 mail = ActionMailer::Base.deliveries.last
165 assert_not_nil mail
165 assert_not_nil mail
166 assert_equal 'Redmine app', mail.from_addrs.first.name
166 assert_equal 'Redmine app', mail.from_addrs.first.name
167 end
167 end
168
168
169 def test_should_not_send_email_without_recipient
169 def test_should_not_send_email_without_recipient
170 news = News.find(:first)
170 news = News.find(:first)
171 user = news.author
171 user = news.author
172 # Remove members except news author
172 # Remove members except news author
173 news.project.memberships.each {|m| m.destroy unless m.user == user}
173 news.project.memberships.each {|m| m.destroy unless m.user == user}
174
174
175 user.pref[:no_self_notified] = false
175 user.pref[:no_self_notified] = false
176 user.pref.save
176 user.pref.save
177 User.current = user
177 User.current = user
178 Mailer.deliver_news_added(news.reload)
178 Mailer.deliver_news_added(news.reload)
179 assert_equal 1, last_email.bcc.size
179 assert_equal 1, last_email.bcc.size
180
180
181 # nobody to notify
181 # nobody to notify
182 user.pref[:no_self_notified] = true
182 user.pref[:no_self_notified] = true
183 user.pref.save
183 user.pref.save
184 User.current = user
184 User.current = user
185 ActionMailer::Base.deliveries.clear
185 ActionMailer::Base.deliveries.clear
186 Mailer.deliver_news_added(news.reload)
186 Mailer.deliver_news_added(news.reload)
187 assert ActionMailer::Base.deliveries.empty?
187 assert ActionMailer::Base.deliveries.empty?
188 end
188 end
189
189
190 def test_issue_add_message_id
190 def test_issue_add_message_id
191 issue = Issue.find(1)
191 issue = Issue.find(1)
192 Mailer.deliver_issue_add(issue)
192 Mailer.deliver_issue_add(issue)
193 mail = ActionMailer::Base.deliveries.last
193 mail = ActionMailer::Base.deliveries.last
194 assert_not_nil mail
194 assert_not_nil mail
195 assert_equal Mailer.message_id_for(issue), mail.message_id
195 assert_equal Mailer.message_id_for(issue), mail.message_id
196 assert_nil mail.references
196 assert_nil mail.references
197 end
197 end
198
198
199 def test_issue_edit_message_id
199 def test_issue_edit_message_id
200 journal = Journal.find(1)
200 journal = Journal.find(1)
201 Mailer.deliver_issue_edit(journal)
201 Mailer.deliver_issue_edit(journal)
202 mail = ActionMailer::Base.deliveries.last
202 mail = ActionMailer::Base.deliveries.last
203 assert_not_nil mail
203 assert_not_nil mail
204 assert_equal Mailer.message_id_for(journal), mail.message_id
204 assert_equal Mailer.message_id_for(journal), mail.message_id
205 assert_equal Mailer.message_id_for(journal.issue), mail.references.first.to_s
205 assert_equal Mailer.message_id_for(journal.issue), mail.references.first.to_s
206 end
206 end
207
207
208 def test_message_posted_message_id
208 def test_message_posted_message_id
209 message = Message.find(1)
209 message = Message.find(1)
210 Mailer.deliver_message_posted(message)
210 Mailer.deliver_message_posted(message)
211 mail = ActionMailer::Base.deliveries.last
211 mail = ActionMailer::Base.deliveries.last
212 assert_not_nil mail
212 assert_not_nil mail
213 assert_equal Mailer.message_id_for(message), mail.message_id
213 assert_equal Mailer.message_id_for(message), mail.message_id
214 assert_nil mail.references
214 assert_nil mail.references
215 assert_select_email do
215 assert_select_email do
216 # link to the message
216 # link to the message
217 assert_select "a[href=?]",
217 assert_select "a[href=?]",
218 "http://mydomain.foo/boards/#{message.board.id}/topics/#{message.id}",
218 "http://mydomain.foo/boards/#{message.board.id}/topics/#{message.id}",
219 :text => message.subject
219 :text => message.subject
220 end
220 end
221 end
221 end
222
222
223 def test_reply_posted_message_id
223 def test_reply_posted_message_id
224 message = Message.find(3)
224 message = Message.find(3)
225 Mailer.deliver_message_posted(message)
225 Mailer.deliver_message_posted(message)
226 mail = ActionMailer::Base.deliveries.last
226 mail = ActionMailer::Base.deliveries.last
227 assert_not_nil mail
227 assert_not_nil mail
228 assert_equal Mailer.message_id_for(message), mail.message_id
228 assert_equal Mailer.message_id_for(message), mail.message_id
229 assert_equal Mailer.message_id_for(message.parent), mail.references.first.to_s
229 assert_equal Mailer.message_id_for(message.parent), mail.references.first.to_s
230 assert_select_email do
230 assert_select_email do
231 # link to the reply
231 # link to the reply
232 assert_select "a[href=?]",
232 assert_select "a[href=?]",
233 "http://mydomain.foo/boards/#{message.board.id}/topics/#{message.root.id}?r=#{message.id}#message-#{message.id}",
233 "http://mydomain.foo/boards/#{message.board.id}/topics/#{message.root.id}?r=#{message.id}#message-#{message.id}",
234 :text => message.subject
234 :text => message.subject
235 end
235 end
236 end
236 end
237
237
238 context("#issue_add") do
238 context("#issue_add") do
239 setup do
239 setup do
240 ActionMailer::Base.deliveries.clear
240 ActionMailer::Base.deliveries.clear
241 Setting.bcc_recipients = '1'
241 Setting.bcc_recipients = '1'
242 @issue = Issue.find(1)
242 @issue = Issue.find(1)
243 end
243 end
244
244
245 should "notify project members" do
245 should "notify project members" do
246 assert Mailer.deliver_issue_add(@issue)
246 assert Mailer.deliver_issue_add(@issue)
247 assert last_email.bcc.include?('dlopper@somenet.foo')
247 assert last_email.bcc.include?('dlopper@somenet.foo')
248 end
248 end
249
249
250 should "not notify project members that are not allow to view the issue" do
250 should "not notify project members that are not allow to view the issue" do
251 Role.find(2).remove_permission!(:view_issues)
251 Role.find(2).remove_permission!(:view_issues)
252 assert Mailer.deliver_issue_add(@issue)
252 assert Mailer.deliver_issue_add(@issue)
253 assert !last_email.bcc.include?('dlopper@somenet.foo')
253 assert !last_email.bcc.include?('dlopper@somenet.foo')
254 end
254 end
255
255
256 should "notify issue watchers" do
256 should "notify issue watchers" do
257 user = User.find(9)
257 user = User.find(9)
258 # minimal email notification options
258 # minimal email notification options
259 user.pref[:no_self_notified] = '1'
259 user.pref[:no_self_notified] = '1'
260 user.pref.save
260 user.pref.save
261 user.mail_notification = false
261 user.mail_notification = false
262 user.save
262 user.save
263
263
264 Watcher.create!(:watchable => @issue, :user => user)
264 Watcher.create!(:watchable => @issue, :user => user)
265 assert Mailer.deliver_issue_add(@issue)
265 assert Mailer.deliver_issue_add(@issue)
266 assert last_email.bcc.include?(user.mail)
266 assert last_email.bcc.include?(user.mail)
267 end
267 end
268
268
269 should "not notify watchers not allowed to view the issue" do
269 should "not notify watchers not allowed to view the issue" do
270 user = User.find(9)
270 user = User.find(9)
271 Watcher.create!(:watchable => @issue, :user => user)
271 Watcher.create!(:watchable => @issue, :user => user)
272 Role.non_member.remove_permission!(:view_issues)
272 Role.non_member.remove_permission!(:view_issues)
273 assert Mailer.deliver_issue_add(@issue)
273 assert Mailer.deliver_issue_add(@issue)
274 assert !last_email.bcc.include?(user.mail)
274 assert !last_email.bcc.include?(user.mail)
275 end
275 end
276 end
276 end
277
277
278 # test mailer methods for each language
278 # test mailer methods for each language
279 def test_issue_add
279 def test_issue_add
280 issue = Issue.find(1)
280 issue = Issue.find(1)
281 valid_languages.each do |lang|
281 valid_languages.each do |lang|
282 Setting.default_language = lang.to_s
282 Setting.default_language = lang.to_s
283 assert Mailer.deliver_issue_add(issue)
283 assert Mailer.deliver_issue_add(issue)
284 end
284 end
285 end
285 end
286
286
287 def test_issue_edit
287 def test_issue_edit
288 journal = Journal.find(1)
288 journal = Journal.find(1)
289 valid_languages.each do |lang|
289 valid_languages.each do |lang|
290 Setting.default_language = lang.to_s
290 Setting.default_language = lang.to_s
291 assert Mailer.deliver_issue_edit(journal)
291 assert Mailer.deliver_issue_edit(journal)
292 end
292 end
293 end
293 end
294
294
295 def test_document_added
295 def test_document_added
296 document = Document.find(1)
296 document = Document.find(1)
297 valid_languages.each do |lang|
297 valid_languages.each do |lang|
298 Setting.default_language = lang.to_s
298 Setting.default_language = lang.to_s
299 assert Mailer.deliver_document_added(document)
299 assert Mailer.deliver_document_added(document)
300 end
300 end
301 end
301 end
302
302
303 def test_attachments_added
303 def test_attachments_added
304 attachements = [ Attachment.find_by_container_type('Document') ]
304 attachements = [ Attachment.find_by_container_type('Document') ]
305 valid_languages.each do |lang|
305 valid_languages.each do |lang|
306 Setting.default_language = lang.to_s
306 Setting.default_language = lang.to_s
307 assert Mailer.deliver_attachments_added(attachements)
307 assert Mailer.deliver_attachments_added(attachements)
308 end
308 end
309 end
309 end
310
310
311 def test_version_file_added
311 def test_version_file_added
312 attachements = [ Attachment.find_by_container_type('Version') ]
312 attachements = [ Attachment.find_by_container_type('Version') ]
313 assert Mailer.deliver_attachments_added(attachements)
313 assert Mailer.deliver_attachments_added(attachements)
314 assert_not_nil last_email.bcc
314 assert_not_nil last_email.bcc
315 assert last_email.bcc.any?
315 assert last_email.bcc.any?
316 assert_select_email do
316 assert_select_email do
317 assert_select "a[href=?]", "http://mydomain.foo/projects/ecookbook/files"
317 assert_select "a[href=?]", "http://mydomain.foo/projects/ecookbook/files"
318 end
318 end
319 end
319 end
320
320
321 def test_project_file_added
321 def test_project_file_added
322 attachements = [ Attachment.find_by_container_type('Project') ]
322 attachements = [ Attachment.find_by_container_type('Project') ]
323 assert Mailer.deliver_attachments_added(attachements)
323 assert Mailer.deliver_attachments_added(attachements)
324 assert_not_nil last_email.bcc
324 assert_not_nil last_email.bcc
325 assert last_email.bcc.any?
325 assert last_email.bcc.any?
326 assert_select_email do
326 assert_select_email do
327 assert_select "a[href=?]", "http://mydomain.foo/projects/ecookbook/files"
327 assert_select "a[href=?]", "http://mydomain.foo/projects/ecookbook/files"
328 end
328 end
329 end
329 end
330
330
331 def test_news_added
331 def test_news_added
332 news = News.find(:first)
332 news = News.find(:first)
333 valid_languages.each do |lang|
333 valid_languages.each do |lang|
334 Setting.default_language = lang.to_s
334 Setting.default_language = lang.to_s
335 assert Mailer.deliver_news_added(news)
335 assert Mailer.deliver_news_added(news)
336 end
336 end
337 end
337 end
338
338
339 def test_news_comment_added
339 def test_news_comment_added
340 comment = Comment.find(2)
340 comment = Comment.find(2)
341 valid_languages.each do |lang|
341 valid_languages.each do |lang|
342 Setting.default_language = lang.to_s
342 Setting.default_language = lang.to_s
343 assert Mailer.deliver_news_comment_added(comment)
343 assert Mailer.deliver_news_comment_added(comment)
344 end
344 end
345 end
345 end
346
346
347 def test_message_posted
347 def test_message_posted
348 message = Message.find(:first)
348 message = Message.find(:first)
349 recipients = ([message.root] + message.root.children).collect {|m| m.author.mail if m.author}
349 recipients = ([message.root] + message.root.children).collect {|m| m.author.mail if m.author}
350 recipients = recipients.compact.uniq
350 recipients = recipients.compact.uniq
351 valid_languages.each do |lang|
351 valid_languages.each do |lang|
352 Setting.default_language = lang.to_s
352 Setting.default_language = lang.to_s
353 assert Mailer.deliver_message_posted(message)
353 assert Mailer.deliver_message_posted(message)
354 end
354 end
355 end
355 end
356
356
357 def test_wiki_content_added
357 def test_wiki_content_added
358 content = WikiContent.find(:first)
358 content = WikiContent.find(:first)
359 valid_languages.each do |lang|
359 valid_languages.each do |lang|
360 Setting.default_language = lang.to_s
360 Setting.default_language = lang.to_s
361 assert_difference 'ActionMailer::Base.deliveries.size' do
361 assert_difference 'ActionMailer::Base.deliveries.size' do
362 assert Mailer.deliver_wiki_content_added(content)
362 assert Mailer.deliver_wiki_content_added(content)
363 end
363 end
364 end
364 end
365 end
365 end
366
366
367 def test_wiki_content_updated
367 def test_wiki_content_updated
368 content = WikiContent.find(:first)
368 content = WikiContent.find(:first)
369 valid_languages.each do |lang|
369 valid_languages.each do |lang|
370 Setting.default_language = lang.to_s
370 Setting.default_language = lang.to_s
371 assert_difference 'ActionMailer::Base.deliveries.size' do
371 assert_difference 'ActionMailer::Base.deliveries.size' do
372 assert Mailer.deliver_wiki_content_updated(content)
372 assert Mailer.deliver_wiki_content_updated(content)
373 end
373 end
374 end
374 end
375 end
375 end
376
376
377 def test_account_information
377 def test_account_information
378 user = User.find(2)
378 user = User.find(2)
379 valid_languages.each do |lang|
379 valid_languages.each do |lang|
380 user.update_attribute :language, lang.to_s
380 user.update_attribute :language, lang.to_s
381 user.reload
381 user.reload
382 assert Mailer.deliver_account_information(user, 'pAsswORd')
382 assert Mailer.deliver_account_information(user, 'pAsswORd')
383 end
383 end
384 end
384 end
385
385
386 def test_lost_password
386 def test_lost_password
387 token = Token.find(2)
387 token = Token.find(2)
388 valid_languages.each do |lang|
388 valid_languages.each do |lang|
389 token.user.update_attribute :language, lang.to_s
389 token.user.update_attribute :language, lang.to_s
390 token.reload
390 token.reload
391 assert Mailer.deliver_lost_password(token)
391 assert Mailer.deliver_lost_password(token)
392 end
392 end
393 end
393 end
394
394
395 def test_register
395 def test_register
396 token = Token.find(1)
396 token = Token.find(1)
397 Setting.host_name = 'redmine.foo'
397 Setting.host_name = 'redmine.foo'
398 Setting.protocol = 'https'
398 Setting.protocol = 'https'
399
399
400 valid_languages.each do |lang|
400 valid_languages.each do |lang|
401 token.user.update_attribute :language, lang.to_s
401 token.user.update_attribute :language, lang.to_s
402 token.reload
402 token.reload
403 ActionMailer::Base.deliveries.clear
403 ActionMailer::Base.deliveries.clear
404 assert Mailer.deliver_register(token)
404 assert Mailer.deliver_register(token)
405 mail = ActionMailer::Base.deliveries.last
405 mail = ActionMailer::Base.deliveries.last
406 assert mail.body.include?("https://redmine.foo/account/activate?token=#{token.value}")
406 assert mail.body.include?("https://redmine.foo/account/activate?token=#{token.value}")
407 end
407 end
408 end
408 end
409
409
410 def test_test
410 def test_test
411 user = User.find(1)
411 user = User.find(1)
412 valid_languages.each do |lang|
412 valid_languages.each do |lang|
413 user.update_attribute :language, lang.to_s
413 user.update_attribute :language, lang.to_s
414 assert Mailer.deliver_test(user)
414 assert Mailer.deliver_test(user)
415 end
415 end
416 end
416 end
417
417
418 def test_reminders
418 def test_reminders
419 Mailer.reminders(:days => 42)
419 Mailer.reminders(:days => 42)
420 assert_equal 1, ActionMailer::Base.deliveries.size
420 assert_equal 1, ActionMailer::Base.deliveries.size
421 mail = ActionMailer::Base.deliveries.last
421 mail = ActionMailer::Base.deliveries.last
422 assert mail.bcc.include?('dlopper@somenet.foo')
422 assert mail.bcc.include?('dlopper@somenet.foo')
423 assert mail.body.include?('Bug #3: Error 281 when updating a recipe')
423 assert mail.body.include?('Bug #3: Error 281 when updating a recipe')
424 assert_equal '1 issue(s) due in the next 42 days', mail.subject
424 assert_equal '1 issue(s) due in the next 42 days', mail.subject
425 end
425 end
426
426
427 def test_reminders_for_users
427 def test_reminders_for_users
428 Mailer.reminders(:days => 42, :users => ['5'])
428 Mailer.reminders(:days => 42, :users => ['5'])
429 assert_equal 0, ActionMailer::Base.deliveries.size # No mail for dlopper
429 assert_equal 0, ActionMailer::Base.deliveries.size # No mail for dlopper
430 Mailer.reminders(:days => 42, :users => ['3'])
430 Mailer.reminders(:days => 42, :users => ['3'])
431 assert_equal 1, ActionMailer::Base.deliveries.size # No mail for dlopper
431 assert_equal 1, ActionMailer::Base.deliveries.size # No mail for dlopper
432 mail = ActionMailer::Base.deliveries.last
432 mail = ActionMailer::Base.deliveries.last
433 assert mail.bcc.include?('dlopper@somenet.foo')
433 assert mail.bcc.include?('dlopper@somenet.foo')
434 assert mail.body.include?('Bug #3: Error 281 when updating a recipe')
434 assert mail.body.include?('Bug #3: Error 281 when updating a recipe')
435 end
435 end
436
436
437 def last_email
437 def last_email
438 mail = ActionMailer::Base.deliveries.last
438 mail = ActionMailer::Base.deliveries.last
439 assert_not_nil mail
439 assert_not_nil mail
440 mail
440 mail
441 end
441 end
442
442
443 def test_mailer_should_not_change_locale
443 def test_mailer_should_not_change_locale
444 Setting.default_language = 'en'
444 Setting.default_language = 'en'
445 # Set current language to italian
445 # Set current language to italian
446 set_language_if_valid 'it'
446 set_language_if_valid 'it'
447 # Send an email to a french user
447 # Send an email to a french user
448 user = User.find(1)
448 user = User.find(1)
449 user.language = 'fr'
449 user.language = 'fr'
450 Mailer.deliver_account_activated(user)
450 Mailer.deliver_account_activated(user)
451 mail = ActionMailer::Base.deliveries.last
451 mail = ActionMailer::Base.deliveries.last
452 assert mail.body.include?('Votre compte')
452 assert mail.body.include?('Votre compte')
453
453
454 assert_equal :it, current_language
454 assert_equal :it, current_language
455 end
455 end
456
456
457 def test_with_deliveries_off
457 def test_with_deliveries_off
458 Mailer.with_deliveries false do
458 Mailer.with_deliveries false do
459 Mailer.deliver_test(User.find(1))
459 Mailer.deliver_test(User.find(1))
460 end
460 end
461 assert ActionMailer::Base.deliveries.empty?
461 assert ActionMailer::Base.deliveries.empty?
462 # should restore perform_deliveries
462 # should restore perform_deliveries
463 assert ActionMailer::Base.perform_deliveries
463 assert ActionMailer::Base.perform_deliveries
464 end
464 end
465
465
466 context "layout" do
466 context "layout" do
467 should "include the emails_header" do
467 should "include the emails_header" do
468 with_settings(:emails_header => "*Header content*") do
468 with_settings(:emails_header => "*Header content*") do
469 assert Mailer.deliver_test(User.find(1))
469 assert Mailer.deliver_test(User.find(1))
470
470
471 assert_select_email do
471 assert_select_email do
472 assert_select ".header" do
472 assert_select ".header" do
473 assert_select "strong", :text => "Header content"
473 assert_select "strong", :text => "Header content"
474 end
474 end
475 end
475 end
476 end
476 end
477 end
477 end
478 end
478 end
479 end
479 end
General Comments 0
You need to be logged in to leave comments. Login now