如何用 Python 发送电子邮件?

2025-02-18 09:23:00
admin
原创
129
摘要:问题描述:这段代码可以正常工作并向我发送电子邮件:import smtplib #SERVER = "localhost" FROM = 'monty@python.com' TO = ["jon@mycompany.com"] # must be a list ...

问题描述:

这段代码可以正常工作并向我发送电子邮件:

import smtplib
#SERVER = "localhost"

FROM = 'monty@python.com'

TO = ["jon@mycompany.com"] # must be a list

SUBJECT = "Hello!"

TEXT = "This message was sent with Python's smtplib."

# Prepare actual message

message = """\nFrom: %s
To: %s
Subject: %s

%s
""" % (FROM, ", ".join(TO), SUBJECT, TEXT)

# Send the mail

server = smtplib.SMTP('myserver')
server.sendmail(FROM, TO, message)
server.quit()

但是如果我尝试将其包装在这样的函数中:

def sendMail(FROM,TO,SUBJECT,TEXT,SERVER):
    import smtplib
    """this is some test documentation in the function"""
    message = """\n        From: %s
        To: %s
        Subject: %s
        %s
        """ % (FROM, ", ".join(TO), SUBJECT, TEXT)
    # Send the mail
    server = smtplib.SMTP(SERVER)
    server.sendmail(FROM, TO, message)
    server.quit()

并调用它我收到以下错误:

 Traceback (most recent call last):
  File "C:/Python31/mailtest1.py", line 8, in <module>
    sendmail.sendMail(sender,recipients,subject,body,server)
  File "C:/Python31sendmail.py", line 13, in sendMail
    server.sendmail(FROM, TO, message)
  File "C:Python31libsmtplib.py", line 720, in sendmail
    self.rset()
  File "C:Python31libsmtplib.py", line 444, in rset
    return self.docmd("rset")
  File "C:Python31libsmtplib.py", line 368, in docmd
    return self.getreply()
  File "C:Python31libsmtplib.py", line 345, in getreply
    raise SMTPServerDisconnected("Connection unexpectedly closed")
smtplib.SMTPServerDisconnected: Connection unexpectedly closed

有人能帮助我理解为什么吗?


解决方案 1:

我建议您一起使用标准包emailsmtplib发送电子邮件。请看以下示例(摘自Python 文档)。请注意,如果您遵循这种方法,“简单”任务确实很简单,而更复杂的任务(如附加二进制对象或发送纯文本/HTML 多部分消息)可以非常快速地完成。

# Import smtplib for the actual sending function
import smtplib

# Import the email modules we'll need
from email.mime.text import MIMEText

# Open a plain text file for reading.  For this example, assume that
# the text file contains only ASCII characters.
with open(textfile, 'rb') as fp:
    # Create a text/plain message
    msg = MIMEText(fp.read())

# me == the sender's email address
# you == the recipient's email address
msg['Subject'] = 'The contents of %s' % textfile
msg['From'] = me
msg['To'] = you

# Send the message via our own SMTP server, but don't include the
# envelope header.
s = smtplib.SMTP('localhost')
s.sendmail(me, [you], msg.as_string())
s.quit()

要将电子邮件发送到多个目的地,您也可以按照Python 文档中的示例进行操作:

# Import smtplib for the actual sending function
import smtplib

# Here are the email package modules we'll need
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart

# Create the container (outer) email message.
msg = MIMEMultipart()
msg['Subject'] = 'Our family reunion'
# me == the sender's email address
# family = the list of all recipients' email addresses
msg['From'] = me
msg['To'] = ', '.join(family)
msg.preamble = 'Our family reunion'

# Assume we know that the image files are all in PNG format
for file in pngfiles:
    # Open the files in binary mode.  Let the MIMEImage class automatically
    # guess the specific image type.
    with open(file, 'rb') as fp:
        img = MIMEImage(fp.read())
    msg.attach(img)

# Send the email via our own SMTP server.
s = smtplib.SMTP('localhost')
s.sendmail(me, family, msg.as_string())
s.quit()

如您所见,对象To中的标头MIMEText必须是由逗号分隔的电子邮件地址组成的字符串。另一方面,函数的第二个参数sendmail必须是字符串列表(每个字符串都是一个电子邮件地址)。

因此,如果您有三个电子邮件地址:person1@example.comperson2@example.comperson3@example.com,您可以执行以下操作(省略明显的部分):

to = ["person1@example.com", "person2@example.com", "person3@example.com"]
msg['To'] = ",".join(to)
s.sendmail(me, to, msg.as_string())

",".join(to)部分从列表中生成单个字符串,并以逗号分隔。

从你的问题中我得知你没有看过Python 教程- 如果你想在 Python 中取得任何进展,这是必须的 - 标准库的文档大多非常出色。

解决方案 2:

当我需要用 Python 发送邮件时,我会使用mailgun API,它可以解决很多发送邮件的麻烦。他们有一个很棒的应用程序/API,允许您每月发送 5,000 封免费电子邮件。

发送电子邮件将是这样的:

def send_simple_message():
    return requests.post(
        "https://api.mailgun.net/v3/YOUR_DOMAIN_NAME/messages",
        auth=("api", "YOUR_API_KEY"),
        data={"from": "Excited User <mailgun@YOUR_DOMAIN_NAME>",
              "to": ["bar@example.com", "YOU@YOUR_DOMAIN_NAME"],
              "subject": "Hello",
              "text": "Testing some Mailgun awesomness!"})

您还可以跟踪事件等,请参阅快速入门指南。

解决方案 3:

我想通过推荐 yagmail 包来帮助您发送电子邮件(我是维护者,很抱歉做广告,但我觉得它确实有帮助!)。

您的完整代码如下:

import yagmail
yag = yagmail.SMTP(FROM, 'pass')
yag.send(TO, SUBJECT, TEXT)

请注意,我为所有参数提供了默认值,例如,如果您想发送给自己,则可以省略TO,如果您不想要主题,也可以省略它。

此外,目标还在于使附加 html 代码或图像(和其他文件)变得非常容易。

您可以在其中放置内容,例如:

contents = ['Body text, and here is an embedded image:', 'http://somedomain/image.png',
            'You can also find an audio file attached.', '/local/path/song.mp3']

哇,发送附件太简单了!如果没有 yagmail,这需要 20 行代码 ;)

此外,如果您设置一次,就无需再次输入密码(并安全存储)。对于您来说,您可以执行以下操作:

import yagmail
yagmail.SMTP().send(contents = contents)

更加简洁!

我邀请你看一下github或者直接使用它来安装pip install yagmail

解决方案 4:

下面是一个 Python 示例3.x,比简单得多2.x

import smtplib
from email.message import EmailMessage
def send_mail(to_email, subject, message, server='smtp.example.cn',
              from_email='xx@example.com'):
    # import smtplib
    msg = EmailMessage()
    msg['Subject'] = subject
    msg['From'] = from_email
    msg['To'] = ', '.join(to_email)
    msg.set_content(message)
    print(msg)
    server = smtplib.SMTP(server)
    server.set_debuglevel(1)
    server.login(from_email, 'password')  # user & password
    server.send_message(msg)
    server.quit()
    print('successfully sent the mail.')

调用此函数:

send_mail(to_email=['12345@qq.com', '12345@126.com'],
          subject='hello', message='Your analysis has done!')

以下可能仅适用于中国用户:

如果您使用126/163、网易邮箱,则需要设置“客户端授权密码”,如下:

在此处输入图片描述

参考:https: //stackoverflow.com/a/41470149/2803344
https://docs.python.org/3/library/email.examples.html#email-examples

解决方案 5:

存在缩进问题。以下代码可以正常工作:

import textwrap

def sendMail(FROM,TO,SUBJECT,TEXT,SERVER):
    import smtplib
    """this is some test documentation in the function"""
    message = textwrap.dedent("""\n        From: %s
        To: %s
        Subject: %s
        %s
        """ % (FROM, ", ".join(TO), SUBJECT, TEXT))
    # Send the mail
    server = smtplib.SMTP(SERVER)
    server.sendmail(FROM, TO, message)
    server.quit()

解决方案 6:

在函数中缩进代码(这是可以的)时,您也缩进了原始消息字符串的行。但前导空格意味着标题行的折叠(连接),如RFC 2822 - Internet 消息格式第 2.2.3 和 3.2.3 节所述:

每个标题字段在逻辑上都是一行字符,包括字段名称、冒号和字段主体。但为了方便起见,并为了处理每行 998/78 个字符的限制,标题字段的字段主体部分可以拆分为多行表示;这称为“折叠”。

在您的调用的函数形式中sendmail,所有行都以空格开头,因此是“展开”(连接)的,并且您正在尝试发送

From: monty@python.com    To: jon@mycompany.com    Subject: Hello!    This message was sent with Python's smtplib.

除了我们的想法之外,smtplib将不再理解To:Subject:标题,因为这些名称仅在行的开头被识别。相反,smtplib将假设一个非常长的发件人电子邮件地址:

monty@python.com    To: jon@mycompany.com    Subject: Hello!    This message was sent with Python's smtplib.

这不会起作用,所以会出现异常。

解决方案很简单:只需保留message原来的字符串即可。这可以通过函数(如 Zeeshan 所建议的)或直接在源代码中完成:

import smtplib

def sendMail(FROM,TO,SUBJECT,TEXT,SERVER):
    """this is some test documentation in the function"""
    message = """\nFrom: %s
To: %s
Subject: %s

%s
""" % (FROM, ", ".join(TO), SUBJECT, TEXT)
    # Send the mail
    server = smtplib.SMTP(SERVER)
    server.sendmail(FROM, TO, message)
    server.quit()

现在展开没有发生,你发送

From: monty@python.com
To: jon@mycompany.com
Subject: Hello!

This message was sent with Python's smtplib.

这就是有效的方法以及您的旧代码所完成的操作。

请注意,我还保留了标题和正文之间的空行以适应RFC的第 3.5 节(这是必需的),并根据 Python 样式指南PEP-0008(这是可选的)将包含内容放在函数之外。

解决方案 7:

确保您已授予发件人和收件人从电子邮件帐户中的未知来源(外部来源)发送电子邮件和接收电子邮件的权限。

import smtplib

#Ports 465 and 587 are intended for email client to email server communication - sending email
server = smtplib.SMTP('smtp.gmail.com', 587)

#starttls() is a way to take an existing insecure connection and upgrade it to a secure connection using SSL/TLS.
server.starttls()

#Next, log in to the server
server.login("#email", "#password")

msg = "Hello! This Message was sent by the help of Python"

#Send the mail
server.sendmail("#Sender", "#Reciever", msg)

解决方案 8:

它可能正在将标签放入您的消息中。在将消息传递给 sendMail 之前,请先打印出消息。

解决方案 9:

值得注意的是,SMTP 模块支持上下文管理器,因此无需手动调用 quit(),这将保证即使发生异常也始终调用它。

    with smtplib.SMTP_SSL('smtp.gmail.com', 465) as server:
        server.ehlo()
        server.login(user, password)
        server.sendmail(from, to, body)

解决方案 10:

我对发送电子邮件的软件包选项并不满意,因此我决定制作并开源我自己的电子邮件发送程序。它易于使用,并且能够满足高级用例。

安装:

pip install redmail

用法:

from redmail import EmailSender
email = EmailSender(
    host="<SMTP HOST ADDRESS>",
    port=<PORT NUMBER>,
)

email.send(
    sender="me@example.com",
    receivers=["you@example.com"],
    subject="An example email",
    text="Hi, this is text body.",
    html="<h1>Hi,</h1><p>this is HTML body</p>"
)

如果您的服务器需要用户和密码,只需将user_name和传递passwordEmailSender

我在该方法中包含了很多特性send

  • 包含附件

  • 将图像直接添加到 HTML 主体中

  • Jinja 模板

  • 开箱即用的更漂亮的 HTML 表格

文档:
https://red-mail.readthedocs.io/en/latest/

源代码:https://github.com/Miksus/red-mail

解决方案 11:

@belter 的答案看起来简单易用,但在大多数现代服务器上不起作用,因为大多数服务器都使用ssl。 以下解决方案稍作修改即可工作。

import smtplib, ssl
from email.message import EmailMessage

PORT = 465
SERVER = "smtp.example.com"
CONTEXT = ssl.create_default_context()
USERNAME = "abc"
PASSWORD = "123"

def send_email(to_email, subject, message, from_email="abc@example.com"):
    msg = EmailMessage()
    msg["Subject"] = subject
    msg["From"] = from_email
    msg["To"] = to_email
    msg.set_content(message)
    server = smtplib.SMTP_SSL(SERVER, PORT, context=CONTEXT)
    server.login(USERNAME, PASSWORD)
    server.send_message(msg)
    server.quit()

send_email(to_email=["def@gmail.com", "hij@gmail.com"], subject="Test mail", message="Testing email")

解决方案 12:

因为我刚刚弄清楚了这是如何工作的,所以我想在这里提出我的意见。

看来您没有在服务器连接设置中指定端口,当我尝试连接到未使用默认端口 25 的 SMTP 服务器时,这对我产生了一点影响。

根据 smtplib.SMTP 文档,您的 ehlo 或 helo 请求/响应应该会自动处理,所以您不必担心这一点(但如果一切都失败了,可能需要确认一下)。

另外要问自己的是,您是否允许 SMTP 服务器本身的 SMTP 连接?对于某些网站(如 GMAIL 和 ZOHO),您必须实际进入并激活电子邮件帐户内的 IMAP 连接。您的邮件服务器可能不允许不是来自“localhost”的 SMTP 连接?需要调查一下。

最后,您可能想尝试在 TLS 上启动连接。现在大多数服务器都需要这种类型的身份验证。

您将看到我在电子邮件中塞入了两个收件人字段。msg['TO'] 和 msg['FROM'] msg 字典项允许在电子邮件本身的标题中显示正确的信息,电子邮件接收端可以在收件人/发件人字段中看到这些信息(您甚至可以在此处添加回复字段)。收件人和发件人字段本身是服务器所需的。我知道我听说过有些电子邮件服务器如果没有正确的电子邮件标题就会拒绝电子邮件。

这是我在一个函数中使用的代码,它可以帮助我使用本地计算机和远程 SMTP 服务器(如图所示的 ZOHO)通过电子邮件发送 *.txt 文件的内容:

def emailResults(folder, filename):

    # body of the message
    doc = folder + filename + '.txt'
    with open(doc, 'r') as readText:
        msg = MIMEText(readText.read())

    # headers
    TO = 'to_user@domain.com'
    msg['To'] = TO
    FROM = 'from_user@domain.com'
    msg['From'] = FROM
    msg['Subject'] = 'email subject |' + filename

    # SMTP
    send = smtplib.SMTP('smtp.zoho.com', 587)
    send.starttls()
    send.login('from_user@domain.com', 'password')
    send.sendmail(FROM, TO, msg.as_string())
    send.quit()

解决方案 13:

另一个使用 Gmail 的实现如下:

import smtplib

def send_email(email_address: str, subject: str, body: str):
"""
send_email sends an email to the email address specified in the
argument.

Parameters
----------
email_address: email address of the recipient
subject: subject of the email
body: body of the email
"""

server = smtplib.SMTP('smtp.gmail.com', 587)
server.starttls()
server.login("email_address", "password")
server.sendmail("email_address", email_address,
                "Subject: {}

{}".format(subject, body))
server.quit()

解决方案 14:

我使用和包编写了一个简单的send_email()电子邮件发送函数(链接至我的文章)。它还使用包来加载发件人电子邮件和密码(请不要在代码中保密!)。我使用 Gmail 作为电子邮件服务。密码是(这里有关于如何生成的Google 文档)。smtplib`emaildotenvApp Password`App Password

import os
import smtplib
from email.message import EmailMessage
from dotenv import load_dotenv
_ = load_dotenv()


def send_email(to, subject, message):
    try:
        email_address = os.environ.get("EMAIL_ADDRESS")
        email_password = os.environ.get("EMAIL_PASSWORD")

        if email_address is None or email_password is None:
            # no email address or password
            # something is not configured properly
            print("Did you set email address and password correctly?")
            return False

        # create email
        msg = EmailMessage()
        msg['Subject'] = subject
        msg['From'] = email_address
        msg['To'] = to
        msg.set_content(message)

        # send email
        with smtplib.SMTP_SSL('smtp.gmail.com', 465) as smtp:
            smtp.login(email_address, email_password)
            smtp.send_message(msg)
        return True
    except Exception as e:
        print("Problem during send email")
        print(str(e))
    return False

上述方法对于简单的电子邮件发送来说没问题。如果您正在寻找更高级的功能,例如 HTML 内容或附件 - 当然可以手动编码,但我建议使用现有的软件包,例如yagmail

Gmail 每日电子邮件数量限制为 500 封。如果每天要发送大量电子邮件,请考虑使用事务性电子邮件服务提供商,例如 Amazon SES、MailGun、MailJet 或 SendGrid。

解决方案 15:

import smtplib

s = smtplib.SMTP(your smtp server, smtp port) #SMTP session

message = "Hii!!!"

s.sendmail("sender", "Receiver", message) # sending the mail

s.quit() # terminating the session

解决方案 16:

只是为了补充答案,以便您的邮件传递系统可扩展。

我建议有一个配置文件(可以是 .json、.yml、.ini 等),其中包含发件人的电子邮件配置、密码和收件人。

这样,您就可以根据您的需要创建不同的可定制项目。

下面是包含 3 个文件(配置、函数和主要文件)的小示例。纯文本邮件。

config_email.ini

[email_1]
sender = test@test.com
password = XXXXXXXXXXX
recipients= ["email_2@test.com", "email_2@test.com"]

[email_2]
sender = test_2@test.com
password = XXXXXXXXXXX
recipients= ["email_2@test.com", "email_2@test.com", "email_3@test.com"]

这些项目将从中调用main.py,并将返回其各自的值。

具有功能的文件functions_email.py

import smtplib,configparser,json
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

def get_credentials(item):
    parse = configparser.ConfigParser()
    parse.read('config_email.ini')
    sender = parse[item]['sender ']
    password = parse[item]['password']
    recipients= json.loads(parse[item]['recipients'])
    return sender,password,recipients

def get_msg(sender,recipients,subject,mail_body):
    msg = MIMEMultipart()
    msg['Subject'] = subject
    msg['From'] = sender 
    msg['To'] = ', '.join(recipients)       
    text = """\n    """+mail_body+""" """
    part1 = MIMEText(text, "plain")
    msg.attach(part1)
    return msg

def send_email(msg,sender,password,recipients):
    s = smtplib.SMTP('smtp.test.com')
    s.login(sender,password)
    s.sendmail(sender, recipients, msg.as_string())
    s.quit()    

文件main.py

from functions_email import *

sender,password,recipients = get_credenciales('email_2')
subject= 'text to subject'
mail_body = 'body....................'
msg = get_msg(sender,recipients ,subject,mail_body)    
send_email(msg,sender,password,recipients)

此致!

解决方案 17:

与其他答案相比,这里没有什么新内容,只是它结合了以下所有内容:

  • 使用 TLS(下面示例中为 STARTTLS)

    • 用于ssl.create_default_context()验证服务器证书(!)

  • 不要使用低级 smtplib 方法

    • ehlo(),不quit()

    • 使用with语句来替换其中的一些

  • 利用EmailMessage类来进一步简化消息的创建和发送

  • 仅用于inspect.cleandoc()允许合理的多行字符串文字

例子:

import inspect
import smtplib
import ssl

from email.message import EmailMessage

# a reasonably secure client context way better than None
ssl_context = ssl.create_default_context()

def mail(message):
    with smtplib.SMTP('mail.example.com', port=587) as c:
        c.starttls(context=ssl_context)
        c.login(username, password)
        c.send_message(message)

msg = EmailMessage()
msg['From'] = 'from@example.com'
msg['To'] = 'to@example.com'
msg['Subject'] = 'hello mail'
msg.set_content(inspect.cleandoc('''
    Dear receiver,

    This is some mail...

    Regards,
    me
    '''))

mail(msg)

解决方案 18:

import smtplib, ssl

port = 587  # For starttls
smtp_server = "smtp.office365.com"
sender_email = "170111018@student.mit.edu.tr"
receiver_email = "professordave@hotmail.com"
password = "12345678"
message = """\nSubject: Final exam

Teacher when is the final exam?"""

def SendMailf():
    context = ssl.create_default_context()
    with smtplib.SMTP(smtp_server, port) as server:
        server.ehlo()  # Can be omitted
        server.starttls(context=context)
        server.ehlo()  # Can be omitted
        server.login(sender_email, password)
        server.sendmail(sender_email, receiver_email, message)
        print("mail send")

解决方案 19:

经过大量摆弄这些例子之后,例如这里,
这现在对我有用:

import smtplib
from email.mime.text import MIMEText

# SMTP sendmail server mail relay
host = 'mail.server.com'
port = 587 # starttls not SSL 465 e.g gmail, port 25 blocked by most ISPs & AWS
sender_email = 'name@server.com'
recipient_email = 'name@domain.com'
password = 'YourSMTPServerAuthenticationPass'
subject = "Server - "
body = "Message from server"

def sendemail(host, port, sender_email, recipient_email, password, subject, body):
    try:
        p1 = f'<p><HR><BR>{recipient_email}<BR>'
        p2 = f'<h2><font color="green">{subject}</font></h2>'
        p3 = f'<p>{body}'
        p4 = f'<p>Kind Regards,<BR><BR>{sender_email}<BR><HR>'
        
        message = MIMEText((p1+p2+p3+p4), 'html')  
        # servers may not accept non RFC 5321 / RFC 5322 / compliant TXT & HTML typos

        message['From'] = f'Sender Name <{sender_email}>'
        message['To'] = f'Receiver Name <{recipient_email}>'
        message['Cc'] = f'Receiver2 Name <>'
        message['Subject'] = f'{subject}'
        msg = message.as_string()

        server = smtplib.SMTP(host, port)
        print("Connection Status: Connected")
        server.set_debuglevel(1)
        server.ehlo()
        server.starttls()
        server.ehlo()
        server.login(sender_email, password)
        print("Connection Status: Logged in")
        server.sendmail(sender_email, recipient_email, msg)
        print("Status: Email as HTML successfully sent")

    except Exception as e:
            print(e)
            print("Error: unable to send email")

# Run
sendemail(host, port, sender_email, recipient_email, password, subject, body)
print("Status: Exit")

解决方案 20:

就您的代码而言,除了不清楚您实际如何调用该函数之外,似乎没有任何根本性错误。我能想到的就是当您的服务器没有响应时,您将收到此 SMTPServerDisconnected 错误。如果您在 smtplib 中查找 getreply() 函数(摘录如下),您就会明白。

def getreply(self):
    """Get a reply from the server.

    Returns a tuple consisting of:

      - server response code (e.g. '250', or such, if all goes well)
        Note: returns -1 if it can't read response code.

      - server response string corresponding to response code (multiline
        responses are converted to a single, multiline string).

    Raises SMTPServerDisconnected if end-of-file is reached.
    """

如果您想这样做(DRY 方法),请查看https://github.com/rreddy80/sendEmails/blob/master/sendEmailAttachments.py上的示例,该示例也使用函数调用来发送电子邮件。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   3975  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   2742  
  本文介绍了以下10款项目管理软件工具:禅道项目管理软件、Freshdesk、ClickUp、nTask、Hubstaff、Plutio、Productive、Targa、Bonsai、Wrike。在当今快速变化的商业环境中,项目管理已成为企业成功的关键因素之一。然而,许多企业在项目管理过程中面临着诸多痛点,如任务分配不...
项目管理系统   80  
  本文介绍了以下10款项目管理软件工具:禅道项目管理软件、Monday、TeamGantt、Filestage、Chanty、Visor、Smartsheet、Productive、Quire、Planview。在当今快速变化的商业环境中,项目管理已成为企业成功的关键因素之一。然而,许多项目经理和团队在管理复杂项目时,常...
开源项目管理工具   88  
  本文介绍了以下10款项目管理软件工具:禅道项目管理软件、Smartsheet、GanttPRO、Backlog、Visor、ResourceGuru、Productive、Xebrio、Hive、Quire。在当今快节奏的商业环境中,项目管理已成为企业成功的关键因素之一。然而,许多企业在选择项目管理工具时常常面临困惑:...
项目管理系统   77  
热门文章
项目管理软件有哪些?
曾咪二维码

扫码咨询,免费领取项目管理大礼包!

云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用