Инструменты пользователя

Инструменты сайта


ci:jenkins-email-notifications-starttls

Jenkins: настройка отправки нотификаций

Введение

В связи с недавней сменой места работы, а так же должности, сейчас я работаю DevOps инженером, по долгу службы приходится много работать с CI (Continuous Iintegration) системами. А в моем случае это одна из наиболее известных и бесплатных CI систем - Jenkins.

Немного истории. Hudson - инструмент непрерывной интеграции, написанный на Java. Запускается в контейнере сервлетов, таких как Apache Tomcat или GlassFish. Поддерживает инструментарий для работы с разными системами контроля версий, включая CVS, Subversion, Mercurial, Git и Clearcase, может собирать проекты Apache Ant и Apache Maven, а также исполнять shell-скрипты и команды Windows.

Основной разработчик Hudson - Косукэ Кавагути - ранее работал в Sun Microsystems и в 2010 году, после поглощения Sun компанией Oracle, основал компанию InfraDNA, нацеленную на коммерческую поддержку инструмента. В феврале 2011 года Кавагути ответвил проект, дав ему наименование Jenkins, в ответ на отказ корпорации Oracle передать права на торговую марку Hudson. В мае 2011 года Oracle отказалась от контроля над проектом и наименованием, предложив целиком передать разработку инструмента под управление Eclipse Foundation

Принято считать, что Jenkins – это инструмент для непрерывной интеграции, и чаще всего этот инструмент рассматривают именно в таком ключе. Но, в реальности, Jenkins стоит рассматривать как настраиваемую платформу. Большое число «плагинов» и свободное определение настроек проекта позволяет использовать Jenkins в таких сценариях, для которых он изначально и не был рассчитан.

Настройка Jenkins

Одна из базовых вещей при использовании Jenkins, хотя это пожалуй справедливо для любой CI системы, это нотификация пользователей о процессе выполнения заданий. И в Jenkins естественно есть базовые механизмы для этого - Email notification плагин, который поставляется вместе с самим Jenkins. Настройки данного плагина доступны в Manage Jenkins → Configure System → E-mail Notification

И в любом задании в Post-Build Actions вы можете добавить отправку почтовых нотификаций

Но с такими настройками, при попытке отправить тестовое письмо, я получал ошибки вида

Failed to send out e-mail

com.sun.mail.smtp.SMTPSendFailedException: 530 5.7.0 Must issue a STARTTLS command first

   at com.sun.mail.smtp.SMTPTransport.issueSendCommand(SMTPTransport.java:2057)
   at com.sun.mail.smtp.SMTPTransport.mailFrom(SMTPTransport.java:1580)
   at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:1097)
   ...
   ...
   ...

такую

Failed to send out e-mail
com.sun.mail.smtp.SMTPSendFailedException: 550 SMTP is available only with SSL or TLS connection enabled.
;
  nested exception is:
   com.sun.mail.smtp.SMTPSenderFailedException: 550 SMTP is available only with SSL or TLS connection enabled.

   at com.sun.mail.smtp.SMTPTransport.issueSendCommand(SMTPTransport.java:2057)
   at com.sun.mail.smtp.SMTPTransport.mailFrom(SMTPTransport.java:1580)
   at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:1097)
   ...
   ...
   ...

или такую

javax.mail.MessagingException: Could not connect to SMTP host: smtp.yandex.ru, port: 587;
  nested exception is:
   javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection?
   at com.sun.mail.smtp.SMTPTransport.openServer(SMTPTransport.java:1934)
   at com.sun.mail.smtp.SMTPTransport.protocolConnect(SMTPTransport.java:638)
   ...
   ...
   ...

в зависимости от используемого почтового провайдера. Как мы видим проблема в том, что Jenkins не использует команду STARTTLS, а пытается пройти аутентификацию по не защищенному каналу, но при этом нормально работает с smtps на 465 порту. Но не все почтовые провайдеры предоставляют smtps, например тот же outlook.com (office 365)

На сегодняшний день очень сложно найти крупного почтового провайдера, который позволит вам использовать незащищенные соединения для аутентификации. А вся проблема в том, что по умолчанию Java Mail API, который и используется в Jenkins для отправки писем, не поддерживает STARTTLS и ее надо включать отдельно.

Для того, чтобы Jenkins, а точнее Java Mail API, начал поддерживать STARTTLS необходимо использовать следующий ключ '-Dmail.smtp.starttls.enable=true'

  • CentOS - /etc/sysconfig/jenkins, параметр JENKINS_JAVA_OPTIONS
  • Ubuntu - /etc/default/jenkins, параметр JAVA_ARGS
# grep JENKINS_JAVA_OPTIONS /etc/sysconfig/jenkins
JENKINS_JAVA_OPTIONS="-Djava.awt.headless=true -Dmail.smtp.starttls.enable=true"

Перезапускаем Jenkins

# service jenkins restart
Shutting down Jenkins                                      [  OK  ]
Starting Jenkins                                           [  OK  ]

И пробуем снова отправить тестовое письмо. Но к сожалению по прежнему получаем ошибку, но на этот раз уже с другим содержимым.

smtp-mail.outlook.com

Failed to send out e-mail

com.sun.mail.smtp.SMTPSendFailedException: 501 5.5.4 Invalid Email address
;
  nested exception is:
   com.sun.mail.smtp.SMTPSenderFailedException: 501 5.5.4 Invalid Email address

   at com.sun.mail.smtp.SMTPTransport.issueSendCommand(SMTPTransport.java:2057)
   at com.sun.mail.smtp.SMTPTransport.mailFrom(SMTPTransport.java:1580)
   at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:1097)
   at javax.mail.Transport.send0(Transport.java:195)
   at javax.mail.Transport.send(Transport.java:124)
   at hudson.tasks.Mailer$DescriptorImpl.doSendTestMail(Mailer.java:566)
   ...
   ...
   ...
   at org.eclipse.jetty.io.nio.SelectChannelEndPoint$1.run(SelectChannelEndPoint.java:52)
   at winstone.BoundedExecutorService$1.run(BoundedExecutorService.java:77)
   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
   at java.lang.Thread.run(Thread.java:745)
Caused by: com.sun.mail.smtp.SMTPSenderFailedException: 501 5.5.4 Invalid Email address

smtp.mail.ru

Failed to send out e-mail

com.sun.mail.smtp.SMTPSendFailedException: 550 not local sender over smtp
;
  nested exception is:
   com.sun.mail.smtp.SMTPSenderFailedException: 550 not local sender over smtp

   at com.sun.mail.smtp.SMTPTransport.issueSendCommand(SMTPTransport.java:2057)
   at com.sun.mail.smtp.SMTPTransport.mailFrom(SMTPTransport.java:1580)
   at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:1097)
   at javax.mail.Transport.send0(Transport.java:195)
   at javax.mail.Transport.send(Transport.java:124)
   at hudson.tasks.Mailer$DescriptorImpl.doSendTestMail(Mailer.java:566)
    ...
   ...
   ...
   at org.eclipse.jetty.io.nio.SelectChannelEndPoint$1.run(SelectChannelEndPoint.java:52)
   at winstone.BoundedExecutorService$1.run(BoundedExecutorService.java:77)
   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
   at java.lang.Thread.run(Thread.java:745)
Caused by: com.sun.mail.smtp.SMTPSenderFailedException: 550 not local sender over smtp

   at com.sun.mail.smtp.SMTPTransport.mailFrom(SMTPTransport.java:1587)

smtp.mail.yahoo.com

Failed to send out e-mail

com.sun.mail.smtp.SMTPSendFailedException: 501 Syntax error in arguments
;
  nested exception is:
   com.sun.mail.smtp.SMTPSenderFailedException: 501 Syntax error in arguments

   at com.sun.mail.smtp.SMTPTransport.issueSendCommand(SMTPTransport.java:2057)
   at com.sun.mail.smtp.SMTPTransport.mailFrom(SMTPTransport.java:1580)
   at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:1097)
   at javax.mail.Transport.send0(Transport.java:195)
   at javax.mail.Transport.send(Transport.java:124)
   at hudson.tasks.Mailer$DescriptorImpl.doSendTestMail(Mailer.java:566)
   ...
   ...
   ...
   at winstone.BoundedExecutorService$1.run(BoundedExecutorService.java:77)
   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
   at java.lang.Thread.run(Thread.java:745)
Caused by: com.sun.mail.smtp.SMTPSenderFailedException: 501 Syntax error in arguments

   at com.sun.mail.smtp.SMTPTransport.mailFrom(SMTPTransport.java:1587)

Честно говоря сами ошибки не очень информативны, лишь подсказывают, что есть какие то проблемы с адресом отправителя. При этом стоит отметить, что если использовать gmail в качестве релея, то все работает нормально, а вот outlook.com, mail.ru, yandex.ru, yahoo.com не хотят отправлять наше тестовое письмо.

Так как доступа к удаленными серверам gmail/outlook у нас естественно нет, то я решил использовать то, что есть под рукой, а именно локальный postfix. И наконец то становится понятна причина ошибок

Feb 16 21:06:38 jenkins postfix/smtpd[28091]: connect from localhost[127.0.0.1]
Feb 16 21:06:38 jenkins postfix/smtpd[28091]: EEB391C1143: client=localhost[127.0.0.1]
Feb 16 21:06:38 jenkins postfix/cleanup[28094]: EEB391C1143: message-id=<184626999.8.1455656798966.JavaMail.jenkins@ci.example.net>
Feb 16 21:06:39 jenkins postfix/qmgr[1896]: EEB391C1143: from=<nobody@nowhere.example.net>, size=600, nrcpt=1 (queue active)
Feb 16 21:06:39 jenkins postfix/smtpd[28091]: disconnect from localhost[127.0.0.1]
Feb 16 21:06:40 jenkins postfix/smtp[28096]: EEB391C1143: host mta6.am0.yahoodns.net[98.138.112.33] said: 421 4.7.0 [GL01] Message from (193.243.156.26) temporarily deferred - 4.16.50. Please refer to http://postmaster.yahoo.com/errors/postmaster-21.html (in reply to MAIL FROM command)
Feb 16 21:06:40 jenkins postfix/smtp[28096]: EEB391C1143: lost connection with mta6.am0.yahoodns.net[98.138.112.33] while sending RCPT TO
Feb 16 21:06:42 jenkins postfix/smtp[28096]: EEB391C1143: to=<relay.test_2015@yahoo.com>, relay=mta6.am0.yahoodns.net[98.138.112.34]:25, delay=3.5, delays=0.03/0/2/1.5, dsn=2.0.0, status=sent (250 ok dirdel)
Feb 16 21:06:42 jenkins postfix/qmgr[1896]: EEB391C1143: removed

А именно адрес отправителя - nobody@nowhere.example.net. Так же стоит заметить, что домен example.net был добавлен уже самим postfix, так как в Jenkins по умолчанию используется не fqdn домен - nobody@nowhere и postfix в соответствии с параметром append_dot_mydomain добавляет к таким адресам значение параметра mydomain.

После небольшого чтения документации находим такую инфомацию.

Jenkins uses the System Admin e-mail address as the sender address for e-mail notification. You can configure this under Manage Jenkins → Configure System. This is under the Jenkins Location header on that page!

Т.е. именно значение System Admin e-mail address и используется в качестве значение mail from, при отправке почтовых сообщений. Но при этом этот параметр вынесен в отдельную секцию Jenkins Location. Лично по мне это не совсем логично, ну да ладно.

После того, как я прописал там реальный почтовый ящик, почтовые нотификации начали работать как и ожидалось.

16:42:14    mv -f $depbase.Tpo $depbase.Po
16:42:14 gcc -O2 -DSYSCONFDIR=\"/usr/local/etc\" -Wno-long-long -Wall -W -Wnested-externs -Wformat=2
16:42:14 Build step 'Execute shell' marked build as failure
16:42:14 Sending e-mails to: alex.hha@gmail.com
16:42:17 Finished: FAILURE

ci/jenkins-email-notifications-starttls.txt · Последние изменения: 2016/02/26 17:31 — root