如何在Linux命令行中通过SMTP服务器发送电子邮件

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在Linux命令行中通过SMTP服务器发送电子邮件相关的知识,希望对你有一定的参考价值。

假定你想配置一个 Linux 应用,用于从你的服务器或桌面客户端发送邮件信息。邮件信息可能是邮件简报、状态更新(如 Cachet)、监控警报(如 Monit)、磁盘时间(如 RAID mdadm)等等。当你要建立自己的 邮件发送服务器 传递信息时 ,你可以替代使用一个免费的公共 SMTP 服务器,从而避免遭受维护之苦。

谷歌的 Gmail 服务就是最可靠的 免费 SMTP 服务器 之一。想要从应用中发送邮件通知,你仅需在应用中添加 Gmail 的 SMTP 服务器地址和你的身份凭证即可。

使用 Gmail 的 SMTP
服务器会遇到一些限制,这些限制主要用于阻止那些经常滥用服务器来发送垃圾邮件和使用邮件营销的家伙。举个例子,你一次只能给至多 100
个地址发送信息,并且一天不能超过 500
个收件人。同样,如果你不想被标为垃圾邮件发送者,你就不能发送过多的不可投递的邮件。当你达到任何一个限制,你的 Gmail
账户将被暂时的锁定一天。简而言之,Gmail 的 SMTP 服务器对于你个人的使用是非常棒的,但不适合商业的批量邮件。

说了这么多,是时候向你们展示 如何在 Linux 环境下使用 Gmail 的 SMTP 服务器 了。

Google Gmail SMTP 服务器设置

如果你想要通过你的应用使用 Gmail 的 SMTP 服务器发送邮件,请牢记接下来的详细说明。

邮件发送服务器 (SMTP 服务器): smtp.gmail.com
使用认证: 是
使用安全连接: 是
用户名: 你的 Gmail 账户 ID (比如 "alice" ,如果你的邮箱为 alice@gmail.com)
密码: 你的 Gmail 密码
端口: 587

确切的配置根据应用会有所不同。在本教程的剩余部分,我将向你展示一些在 Linux 上使用 Gmail SMTP 服务器的应用示例。

从命令行发送邮件

作为第一个例子,让我们尝试最基本的邮件功能:使用 Gmail SMTP 服务器从命令行发送一封邮件。为此,我将使用一个称为 mutt 的命令行邮件客户端。

先安装 mutt:

对于 Debian-based 系统:
$ sudo apt-get install mutt

对于 Red Hat based 系统:
$ sudo yum install mutt

创建一个 mutt 配置文件(~/.muttrc),并和下面一样,在文件中指定 Gmail SMTP 服务器信息。将 替换成自己的 Gmail ID。注意该配置只是为了发送邮件而已(而非接收邮件)。
$ vi ~/.muttrc
set from = "@gmail.com"set realname = "Dan Nanni"set smtp_url = "smtp://@smtp.gmail.com:587/"set smtp_pass = ""

一切就绪,使用 mutt 发送一封邮件:
$ echo "This is an email body." | mutt -s "This is an email subject" alice@yahoo.com

想在一封邮件中添加附件,使用 "-a" 选项
$ echo "This is an email body." | mutt -s "This is an email subject" alice@yahoo.com -a ~/test_attachment.jpg

使用 Gmail SMTP 服务器意味着邮件将显示是从你 Gmail 账户发出的。换句话说,收件人将视你的 Gmail 地址为发件人地址。如果你想要使用自己的域名作为邮件发送方,你需要使用 Gmail SMTP 转发服务。

当服务器重启时发送邮件通知

如果你在 虚拟专用服务器(VPS)
上跑了些重要的网站,建议监控 VPS 的重启行为。作为一个更为实用的例子,让我们研究如何在你的 VPS
上为每一次重启事件建立邮件通知。这里假设你的 VPS 上使用的是 systemd,并向你展示如何为自动邮件通知创建一个自定义的 systemd
启动服务。

首先创建下面的脚本 reboot_notify.sh,用于负责邮件通知。
$ sudo vi /usr/local/bin/reboot_notify.sh

#!/bin/sh

echo "`hostname` was rebooted on `date`" | mutt -F /etc/muttrc -s "Notification on `hostname`" alice@yahoo.com
$ sudo chmod +x /usr/local/bin/reboot_notify.sh

在这个脚本中,我使用 "-F" 选项,用于指定系统级的 mutt 配置文件位置。因此不要忘了创建 /etc/muttrc 文件,并如前面描述的那样填入 Gmail SMTP 信息。

现在让我们创建如下一个自定义的 systemd 服务。
$ sudo mkdir -p /usr/local/lib/systemd/system$ sudo vi /usr/local/lib/systemd/system/reboot-task.service

[Unit]
Description=Send a notification email when the server gets rebooted
DefaultDependencies=no
Before=reboot.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/reboot_notify.sh

[Install]
WantedBy=reboot.target

在创建服务后,添加并启动该服务。
$ sudo systemctl enable reboot-task$ sudo systemctl start reboot-task

从现在起,在每次 VPS 重启时,你将会收到一封通知邮件。

通过服务器使用监控发送邮件通知

作为最后一个例子,让我展示一个现实生活中的应用程序,Monit,这是一款极其有用的服务器监控应用程序。它带有全面的 VPS 监控能力(比如 CPU、内存、进程、文件系统)和邮件通知功能。

如果你想要接收 VPS 上由 Monit 产生的任何事件的邮件通知,你可以在 Monit 配置文件中添加以下 SMTP 信息。

set mailserver smtp.gmail.com port 587
username "" password ""
using tlsv12

set mail-format
from: @gmail.com
subject: $SERVICE $EVENT at $DATE on $HOST
message: Monit $ACTION $SERVICE $EVENT at $DATE on $HOST : $DESCRIPTION.

Yours sincerely,
Monit


# the person who will receive notification emails
set alert alice@yahoo.com

这是一个因为 CPU 负载超载而由 Monit 发送的邮件通知的例子。
参考技术A 可以用sendemail发送邮件,http://blog.uouo123.com/post/807.html

在 JAVA 中通过 gmail smtp 服务器发送电子邮件

【中文标题】在 JAVA 中通过 gmail smtp 服务器发送电子邮件【英文标题】:Sending Email via gmail smtp server in JAVA 【发布时间】:2013-03-13 22:04:09 【问题描述】:

这段代码有什么问题?不知何故,它进入了Transport.send(message); 行的无限循环,没有错误消息,没有异常,只是可能无限循环(我不知道,因为我等待的时间不超过 5-10 分钟)

final String username = "<mail_name>";
final String password = "<password>";

Properties props = new Properties();
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.starttls.enable", "true");
props.put("mail.smtp.host", "smtp.gmail.com");
props.put("mail.smtp.port", "465");

Session session = Session.getInstance(props,
        new javax.mail.Authenticator() 
            protected PasswordAuthentication getPasswordAuthentication() 
                return new PasswordAuthentication(username, password);
            
        );

try 

    Message message = new MimeMessage(session);
    message.setFrom(new InternetAddress("<mail_from>@gmail.com"));
    message.setRecipients(Message.RecipientType.TO,
            InternetAddress.parse("<mail_to>@gmail.com"));
    message.setSubject("Test Subject");
    message.setText("Test");

    Transport.send(message);

    System.out.println("Done");

 catch (MessagingException e) 
    throw new RuntimeException(e);

【问题讨论】:

我建议在MessagingException 之后添加一个catch (Exception e),以查看是否会引发其他类型的异常。还要添加一个finally 块。您还可以添加log4j.xml 并将javax.mail 类设置为DEBUG,看看还会发生什么。 很好的提示,谢谢!会测试它 不幸的是仍在 Transport.send(message) 线上等待...有人可以验证此代码的正确性吗? 【参考方案1】:

使用Simple Java Mail 应该很简单:

Email email = new Email();

email.setFromAddress("lollypop", "lol.pop@somemail.com");
email.addRecipient("C.Cane", "candycane@candyshop.org", RecipientType.TO);
email.setText("We should meet up!");
email.setTextHTML("<b>We should meet up!</b>");
email.setSubject("hey");

new Mailer("smtp.gmail.com", 25, "your user", "your password", TransportStrategy.SMTP_TLS).sendMail(email);
new Mailer("smtp.gmail.com", 587, "your user", "your password", TransportStrategy.SMTP_TLS).sendMail(email);
new Mailer("smtp.gmail.com", 465, "your user", "your password", TransportStrategy.SMTP_SSL).sendMail(email);

如果您启用了双因素登录,则需要从您的 Google 帐户生成application specific password。

【讨论】:

【参考方案2】:

好的。它比我第一次提出的要复杂一些......总结一下我得到了什么:

有一个非常有用的命令:session.setDebug(true);。如果你设置为真,每一个重要的进程都会被调试到控制台。我建议使用它。 第二台计算机只能使用安全选项,您可以切换这台计算机:Transport transport = session.getTransport("smtps"); 而不是非安全 smtp... JavaMail API 传输对象也将处理端口(分别为 smtp: 587 , smtps: 465)

你也可以使用Transport类的静态方法发送消息和(之前保存,非静态sendMessage方法不会保存消息),但是这次你需要使用javax.mail.Authenticator会话创建,如下所示:

Session session = Session.getInstance(props,         new javax.mail.Authenticator() 
    protected PasswordAuthentication getPasswordAuthentication() 
        return new PasswordAuthentication("login", "password");
    

);

1.4.2 JavaMailApi 对于这个问题除了 1.4.7 版本还有另一个异常...

如果不使用,则无法使用静态方法进行身份验证。如果你使用实例方法,你可以。

一台计算机有 maven 并获得了 1.4.2 版本的 JavaMail API。第二台电脑有一个下载的库,版本为 1.4.7,我想这也弄乱了东西 第一个comp Netbeans,第二个comp Intellij... +1) 互联网上有很多陈旧且糟糕的示例代码,这使得正确使用此 API 变得更加困难。

太乱了,但有一些基本概念应该重点关注...

【讨论】:

【参考方案3】:

我在这里进行了一些更改,这对我来说很好用:

Session session = Session.getInstance(props,null);

你像你一样实例化消息对象。最后:

Transport transport = session.getTransport("smtp");
String mfrom = "yourGmailUsernameWithout@"// example laabidiraissi 
transport.connect("smtp.gmail.com", mfrom, "thepassword");
transport.sendMessage(message, message.getAllRecipients());

编辑,请您帮我一个忙,复制/粘贴并尝试这个示例并显示它显示的内容:

package com.test;

import java.util.Properties;

import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;

import org.junit.Test;

public class EmailService 

@Test
public void test()
    Properties props = System.getProperties();
    props.put("mail.smtp.starttls.enable", true); // added this line
    props.put("mail.smtp.host", "smtp.gmail.com");
    props.put("mail.smtp.user", "username");
    props.put("mail.smtp.password", "password");
    props.put("mail.smtp.port", "587");
    props.put("mail.smtp.auth", true);



    Session session = Session.getInstance(props,null);
    MimeMessage message = new MimeMessage(session);

    System.out.println("Port: "+session.getProperty("mail.smtp.port"));

    // Create the email addresses involved
    try 
        InternetAddress from = new InternetAddress("username");
        message.setSubject("Yes we can");
        message.setFrom(from);
        message.addRecipients(Message.RecipientType.TO, InternetAddress.parse("receivermail"));

        // Create a multi-part to combine the parts
        Multipart multipart = new MimeMultipart("alternative");

        // Create your text message part
        BodyPart messageBodyPart = new MimeBodyPart();
        messageBodyPart.setText("some text to send");

        // Add the text part to the multipart
        multipart.addBodyPart(messageBodyPart);

        // Create the html part
        messageBodyPart = new MimeBodyPart();
        String htmlMessage = "Our html text";
        messageBodyPart.setContent(htmlMessage, "text/html");


        // Add html part to multi part
        multipart.addBodyPart(messageBodyPart);

        // Associate multi-part with message
        message.setContent(multipart);

        // Send message
        Transport transport = session.getTransport("smtp");
        transport.connect("smtp.gmail.com", "username", "password");
        System.out.println("Transport: "+transport.toString());
        transport.sendMessage(message, message.getAllRecipients());


     catch (AddressException e) 
        // TODO Auto-generated catch block
        e.printStackTrace();
     catch (MessagingException e) 
        // TODO Auto-generated catch block
        e.printStackTrace();
    


【讨论】:

谢谢,但 mail.smtp.auth 属性已经存在...而且我也尝试过使用其他端口。 对不起 auth 属性,这是我的错,我没看到。 如果尝试使用 25 或 587 端口,无论如何检查您的解决方案...线程“main”中的异常 java.lang.RuntimeException:javax.mail.MessagingException:无法连接到 SMTP 主机: smtp.gmail.com,端口:25;嵌套异常是:java.net.ConnectException:连接被拒绝:连接 还是一样的异常,会不会是我的网络配置不对? 终于有好消息了,我们有一些例外。你的例外是经典的:***.com/questions/7158951/…【参考方案4】:

我可以重现您问题中描述的行为并修复它。

send 方法卡在

SMTPTransport(Service).connect(String, int, String, String) line: 308   

连接不成功,因为您的 gmail smtp 主机端口错误:465

改成587

props.put("mail.smtp.port", "587");

它会起作用的。

【讨论】:

是的,不知道我为什么要骑465端口,但无论如何,它仍然无法正常工作:( 您现在遇到什么异常/错误?您的 java.exe 是否允许通过防火墙? This:java.lang.RuntimeException: javax.mail.MessagingException: 无法连接到 SMTP 主机:smtp.gmail.com,端口:25;嵌套异常是:java.net.ConnectException:连接被拒绝:连接我关闭了整个 Windows 防火墙.. 您的应用似乎不支持 SSL。 smtp.gmail.com 需要安全连接,否则您将不得不选择另一个主机 see google support page。您可能需要通过获取支持安全协议smtpsTransport 实例来明确指定它,并使用它来发送您的消息。请参考accepted answer for this question

以上是关于如何在Linux命令行中通过SMTP服务器发送电子邮件的主要内容,如果未能解决你的问题,请参考以下文章

EmailBackend 用于在 Django 中通过多个 SMTP 发送电子邮件

如何检查 smtp 是不是从命令行(Linux)工作 [关闭]

在 Codeigniter 3 中通过 Office365 帐户发送电子邮件 - 连接超时

使用 Gmail 在 codeigniter 中通过电子邮件类发送电子邮件

如何在 php 中通过 gmail 使用 mail()

如何在 C# 中通过电子邮件发送本地链接(共享服务器链接)?