Kaynağa Gözat

first version

WKJay 6 yıl önce
işleme
89624c7fbe

+ 504 - 0
LICENSE.txt

@@ -0,0 +1,504 @@
+                  GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+(This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.)
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+                  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                            NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    {description}
+    Copyright (C) {year} {fullname}
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
+    USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random
+  Hacker.
+
+  {signature of Ty Coon}, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!

+ 21 - 0
SConscript

@@ -0,0 +1,21 @@
+from building import *
+
+# get current directory
+cwd     = GetCurrentDir()
+# The set of source files associated with this SConscript file.
+src     = Split("""
+src/smtp_client_data.c
+src/smtp_client.c
+""")
+
+if GetDepend(['SMTP_CLIENT_USING_TLS']):
+    src += Glob('src/smtp_client_tls.c')
+
+if GetDepend(['SMTP_CLIENT_USING_SAMPLE']):
+    src += Glob('example/smtp_client_example.c')
+
+path    = [cwd + '/inc']
+
+group = DefineGroup('smtp_client', src, depend = ['PKG_USING_SMTP_CLIENT'], CPPPATH = path)
+
+Return('group')

+ 85 - 0
example/smtp_client_example.c

@@ -0,0 +1,85 @@
+/*************************************************
+ Copyright (c) 2019
+ All rights reserved.
+ File name:     smtp_client_example.c
+ Description:   smtp发送邮件示例邮件
+ History:
+ 1. Version:    
+    Date:       2019-10-14
+    Author:     wangjunjie
+    Modify:     
+*************************************************/
+#include "smtp_client.h"
+#include "rtthread.h"
+
+//若使用TLS加密则需要更大的堆栈空间
+#ifdef SMTP_CLIENT_USING_TLS
+#define SMTP_CLIENT_THREAD_STACK_SIZE 4096
+#else
+#define SMTP_CLIENT_THREAD_STACK_SIZE 2048
+#endif
+
+/*
+ *邮件信息相关宏定义
+ */
+//smtp 服务器域名
+#define SMTP_SERVER_ADDR "smtp.qq.com"
+//smtp 服务器端口号
+#define SMTP_SERVER_PORT "25"
+//smtp 登录用户名
+#define SMTP_USERNAME    ""
+//smtp 登录密码(或凭证)
+#define SMTP_PASSWORD    ""
+//smtp 邮件发送方(必须为登录用户名)
+#define SMTP_MAIL_FROM   SMTP_USERNAME
+//smtp 邮件接收方
+#define SMTP_RCPT_TO     ""
+//邮件主题
+#define SMTP_SUBJECT     "SMTP TEST"
+
+
+//邮件内容
+char *content = "THIS IS SMTP TEST\r\n"
+                "HELLO SMTP\r\n"
+                "--------------------------------------\r\n"
+                "based on --->   RT-Thread\r\n"
+                "based on ---> SMTP_CLIENT\r\n";
+                
+void smtp_thread(void *param)
+{
+    //手动延时等待网络初始化成功
+    rt_thread_delay(10000);
+
+    //初始化smtp客户端
+    smtp_clinet_init();
+    //设置服务器地址
+    smtp_set_server_addr(SMTP_SERVER_ADDR, ADDRESS_TYPE_DOMAIN, SMTP_SERVER_PORT);
+    //设置服务器认证信息
+    smtp_set_auth(SMTP_USERNAME, SMTP_PASSWORD);
+
+    //发送邮件
+    rt_kprintf("\r\n[smtp]: O > start to send mail\r\n");
+    if (smtp_send_mail(SMTP_MAIL_FROM, SMTP_RCPT_TO, SMTP_SUBJECT, content) == 0)
+    {
+        //发送成功
+        rt_kprintf("\r\n[smtp]: O > send mail success!\r\n");
+    }
+    else
+    {
+        //发送失败
+        rt_kprintf("\r\n[smtp]: X > send mail fail!\r\n");
+    }
+}
+
+int smtp_thread_entry(void)
+{
+    rt_thread_t smtp_client_tid;
+    //创建邮件发送线程(如果选择在主函数中直接调用邮件发送函数,需要注意主函数堆栈大小,必要时调大)
+    smtp_client_tid = rt_thread_create("smtp", smtp_thread, RT_NULL, SMTP_CLIENT_THREAD_STACK_SIZE, 20, 5);
+    if (smtp_client_tid != RT_NULL)
+    {
+        rt_thread_startup(smtp_client_tid);
+    }
+    return RT_EOK;
+}
+INIT_APP_EXPORT(smtp_thread_entry);

+ 18 - 0
inc/smtp_client.h

@@ -0,0 +1,18 @@
+#ifndef __SMTP_H
+#define __SMTP_H
+#include <stdint.h>
+
+//域名类型
+#define ADDRESS_TYPE_DOMAIN 0
+//IP地址类型
+#define ADDRESS_TYPE_IP 1
+
+//smtp服务初始化
+void smtp_clinet_init(void);
+//设置smtp服务器地址和端口
+int smtp_set_server_addr(const char *server_addr, uint8_t addr_type, const char *port);
+//设置smtp服务器的用户名密码
+int smtp_set_auth(const char *username, const char *password);
+//发送邮件
+int smtp_send_mail(char *from, char *to, char *subject, char *body);
+#endif /* __SMTP_H */

+ 8 - 0
inc/smtp_client_data.h

@@ -0,0 +1,8 @@
+#ifndef __SMTP_DATA_H
+#define __SMTP_DATA_H
+
+#include <stdint.h>
+
+uint32_t smtp_base64_encode(char *target, uint32_t target_len, const char *source, uint32_t source_len);
+
+#endif /* __SMTP_DATA_H */

+ 119 - 0
inc/smtp_client_private.h

@@ -0,0 +1,119 @@
+#ifndef __SMTP_PRIVATE_H
+#define __SMTP_PRIVATE_H
+#include <stdint.h>
+#include <rtthread.h>
+
+#ifdef SMTP_CLIENT_ENABLE_DEBUG_LOG
+#define SMTP_LOG rt_kprintf
+#else
+#define SMTP_LOG(...)
+#endif
+
+#ifdef SMTP_CLIENT_USING_TLS
+#include <tls_certificate.h>
+#include <tls_client.h>
+#endif
+
+#define SMTP_MAX_ADDR_LEN 100
+#define SMTP_MAX_AUTH_LEN 50
+#define SMTP_SEND_CMD_MAX_LEN 100
+#define SMTP_SEND_DATA_HEAD_MAX_LENGTH 128
+#define SMTP_SEND_DATA_MAX_LEN 512
+#define SMTP_RESPONSE_MAX_LEN 512
+
+#ifdef SMTP_CLIENT_USING_TLS
+//缓冲区大小
+#define MBEDTLS_READ_BUFFER_LEN 1024
+#endif
+
+//smtp 会话阶段
+enum smtp_session_state
+{
+    SMTP_NULL,
+    SMTP_HELO,
+    SMTP_START_TLS,
+    SMTP_FINISH_START_TLS,
+    SMTP_AUTH_LOGIN,
+    SMTP_MAIL,
+    SMTP_RCPT,
+    SMTP_DATA,
+    SMTP_BODY,
+    SMTP_QUIT,
+    SMTP_CLOSED
+};
+
+//smtp 会话结构
+typedef struct
+{
+    //会话状态
+    enum smtp_session_state state;
+    //会话超时时间,如果时间为0,标志超时,则自动关闭连接
+    uint16_t timer;
+    //smtp服务器域名
+    const char *server_domain;
+    //smtp服务器ip
+    const char *server_ip;
+    //smtp服务器端口号
+    const char *server_port;
+    //用户名
+    char username[SMTP_MAX_AUTH_LEN * 2];
+    //密码(有些邮箱服务器需要的是用户凭据)
+    char password[SMTP_MAX_AUTH_LEN * 2];
+    //邮件源地址
+    char *address_from;
+    //邮件目的地址
+    char *address_to;
+    //邮件主题
+    char *subject;
+    //邮件内容
+    char *body;
+    //smtp连接句柄
+    int conn_fd;
+#ifdef SMTP_CLIENT_USING_TLS
+    //tls会话
+    MbedTLSSession *tls_session;
+#endif
+} smtp_session_t;
+
+extern smtp_session_t smtp_session;
+
+#define SMTP_RESP_220 "220"
+#define SMTP_RESP_235 "235"
+#define SMTP_RESP_250 "250"
+#define SMTP_RESP_334 "334"
+#define SMTP_RESP_354 "354"
+#define SMTP_RESP_LOGIN_UNAME "VXNlcm5hbWU6"
+#define SMTP_RESP_LOGIN_PASS "UGFzc3dvcmQ6"
+
+#define SMTP_CMD_EHLO "EHLO DM11\r\n"
+#define SMTP_CMD_AUTHLOGIN "AUTH LOGIN\r\n"
+#define SMTP_CMD_STARTTLS "STARTTLS\r\n"
+#define SMTP_CMD_MAIL_HEAD "MAIL FROM: <"
+#define SMTP_CMD_MAIL_END ">\r\n"
+#define SMTP_CMD_RCPT_HEAD "RCPT TO: <"
+#define SMTP_CMD_RCPT_END ">\r\n"
+#define SMTP_CMD_DATA "DATA\r\n"
+#define SMTP_CMD_HEADER_1 "From: <"
+#define SMTP_CMD_HEADER_2 ">\r\nTo: <"
+#define SMTP_CMD_HEADER_3 ">\r\nSubject: "
+#define SMTP_CMD_HEADER_4 "\r\n\r\n"
+#define SMTP_CMD_BODY_FINISHED "\r\n.\r\n"
+#define SMTP_CMD_QUIT "QUIT\r\n"
+
+#ifdef SMTP_CLIENT_USING_TLS
+//向SSL/TLS中写入数据
+int smtp_mbedtls_client_write(MbedTLSSession *tls_session, char *buf);
+//从 SSL/TLS 中读取数据
+int smtp_mbedtls_client_read(MbedTLSSession *tls_session, char *buf, size_t len);
+
+//smtp mbedtls 网络连接(用于starttls方式)
+int smtp_connect_server_by_starttls(void);
+//开启starttls
+int smtp_mbedtls_starttls(MbedTLSSession *tls_session);
+//smtp 以tls加密方式连接服务器
+int smtp_connect_server_by_tls(void);
+//smtp 关闭tls连接,释放资源
+int smtp_mbedtls_close_connection(void);
+#endif
+
+#endif /* __SMTP_PRIVATE_H */

+ 152 - 0
readme.md

@@ -0,0 +1,152 @@
+# SMTP_CLIENT
+
+## 简介
+
+这是一个基于RT-Thread的SMTP软件包,其支持普通的25端口,同时也支持465和587这两个加密端口。该软件包的使用非常简单方便,如果是基于RT-Thread操作系统,则无需进行任何移植操作即可使用,且仅需调用几个简单的接口即可实现不同端口的邮件发送功能。
+
+## 特性
+
+- 支持25端口
+- 支持加密功能,支持465,587端口。(有些邮件服务器可能不支持其中的某个端口,用户使用前需了解自己所选用的邮件服务器支持哪个端口的smtp功能)
+- 使用简单,无需了解SMTP协议,设置好一些必要参数后仅需一个接口即可实现邮件发送。
+
+## 软件包使用说明
+
+### 准备工作
+ 
+#### Env 配置说明
+
+首先需要下载 SMTP_CLIENT 软件包,并将软件包加入到项目中。在 BSP 目录下使用 menuconfig 命令打开 Env 配置界面,在 `RT-Thread online packages → IoT - internet of things` 中选择 SMTP_CLIENT 软件包,具体路径如下:
+
+```C
+
+RT-Thread online packages
+    IoT - internet of things  --->
+         [*] smtp_client:smtp client package for rt-thread  --->
+                Version (latest) --->
+            [*] use 465/587 port(encrypted port)
+            [ ] enable debug log information
+                smtp_client Options --->
+                    [*] smtp client example
+
+```
+
+- **Version:** 配置软件版本
+- **use 465/587 port(encrypted port):** 使用加密端口,选中后会将 **mbedtls** 软件包加入编译,同时开启 465和587 两个加密端口的支持。
+- **enable debug log information:** 使能调试打印信息
+- **smtp client example:** 加入示例文件
+
+**注意:加入示例文件后不能直接下载使用,默认示例中缺少SMTP的个人参数,需要用户补全自己的用户名密码及接收方邮箱等信息!**
+
+#### 注意事项
+
+ - 开启加密功能后会占用比较大的RAM空间,请根据自己使用的硬件平台决定是否选用加密。并且适当调大调用发送功能的线程的堆栈大小。(推荐大于4096)
+ - 有些邮件服务器不支持某个加密端口或者默认关闭,使用者需要确认自己选用的邮件服务器所支持的端口,并且确认已经打开邮件服务器的SMTP功能。
+ - 若用户在使用的过程中出现加密有关的错误,请参照 RT-Thread **mbedtls** 软件包的说明文档。
+
+ ### 使用说明
+
+ #### 使用步骤
+
+ 1. 调用 `smtp_clinet_init` 函数初始化 smtp_client 客户端
+ 2. 调用 `smtp_set_server_addr` 函数设置服务器的地址及端口
+ 3. 调用 `smtp_set_auth` 函数设置服务器认证信息
+ 4. 调用 `smtp_send_mail` 函数发送邮件
+
+ #### API详解
+
+ ##### 1、初始化SMTP客户端
+
+ ```C
+
+ void smtp_clinet_init(void);
+ 
+ ```
+
+该函数主要用于初始化 smtp 会话结构。
+
+##### 2、设置SMTP服务器地址及端口
+
+```C
+
+int smtp_set_server_addr(const char *server_addr, uint8_t addr_type, const char *port);
+
+```
+
+|参数|说明|
+|---|---|
+|server_addr|服务器地址|
+|addr_type|地址类型(域名或IP)|
+|port|端口|
+
+|返回值|说明|
+|----|----|
+|0|设置成功|
+|-1|设置失败|
+
+该函数用于设置 smtp 服务器地址及端口,地址类型为域名类型和IP类型,分别对应宏 `ADDRESS_TYPE_DOMAIN` 与 ` ADDRESS_TYPE_IP` .**需要注意的是,由于时间仓促及其需求不是很大,目前仅支持域名连接,但如果有需求,在后续版本中会加入IP连接。当然程序中已预留接口,需求紧的用户可使用接口进行拓展**。
+
+##### 3、设置 smtp 服务器认证信息
+
+```C
+
+int smtp_set_auth(const char *username, const char *password);
+
+```
+
+|参数|说明|
+|---|---|
+|username|服务器用户名|
+|password|认证密码或凭据|
+
+|返回值|说明|
+|----|----|
+|0|设置成功|
+|-1|设置失败|
+
+该函数用于设置 smtp 服务器的认证信息,需要注意有些服务器需要用 **凭据** 而非用户登录邮箱时的密码进行认证,用户在连接服务器时需要确认自己所用服务器的认证方式。
+
+##### 4、发送邮件
+
+```C
+
+int smtp_send_mail(char *from, char *to, char *subject, char *body);
+
+```
+
+|参数|说明|
+|---|---|
+|from|发送者邮箱地址|
+|to|接收者邮箱地址|
+|subject|主题|
+|body|内容|
+
+|返回值|说明|
+|----|----|
+|0|发送成功|
+|-1|发送失败|
+
+该函数为邮件发送函数,在用户设置好服务器的连接参数后,可以直接调用该函数进行邮件的发送。需要注意的是,发送者邮箱地址必须和登录用户名相同。
+
+ #### 宏配置说明
+
+若用户在使用过程中发现默认的配置无法满足自身的使用需求,用户可以进入 `smtp_client_private.h` 文件对相关宏定义参数进行配置:
+
+|宏|说明|
+|---|---|
+|SMTP_MAX_ADDR_LEN|邮箱地址最大长度|
+|SMTP_MAX_AUTH_LEN|认证信息最长度|
+|SMTP_SEND_CMD_MAX_LEN|SMTP指令发送最大长度|
+|SMTP_SEND_DATA_HEAD_MAX_LENGTH|邮件头最大长度|
+|SMTP_SEND_DATA_MAX_LEN|邮件内容最大长度|
+|SMTP_RESPONSE_MAX_LEN|服务器响应数据最大长度|
+
+一般情况下,用户需要根据自己内容的大小对 `SMTP_SEND_DATA_MAX_LEN` 进行配置即可。
+
+## 联系方式&感谢
+
+- 维护: WKJay
+- 主页:https://github.com/WKJay/SMTP_CLIENT
+- email: 1931048074@qq.com
+- 若在使用过程中有任何问题,请与作者取得联系。同时欢迎大家参与到该软件包的开发与维护中来,共同创建一个更加完善、稳定的软件包。
+

+ 734 - 0
src/smtp_client.c

@@ -0,0 +1,734 @@
+/*************************************************
+ Copyright (c) 2019
+ All rights reserved.
+ File name:     smtp_client.c
+ Description:   smtp源文件
+ History:
+ 1. Version:    
+    Date:       2019-10-10
+    Author:     wangjunjie
+    Modify:     
+*************************************************/
+
+#include <stdint.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <dfs_posix.h>
+
+#include "smtp_client_private.h"
+#include "smtp_client_data.h"
+#include "smtp_client.h"
+#include "netdb.h"
+
+smtp_session_t smtp_session;
+
+/**
+ * Name:    smtp_clinet_init
+ * Brief:   初始化smtp客户端
+ * Input:   None
+ * Output:  None
+ */
+void smtp_clinet_init(void)
+{
+    memset(&smtp_session, 0, sizeof(smtp_session_t));
+}
+
+/**
+ * Name:    smtp_close_connection
+ * Brief:   smtp关闭连接,释放资源
+ * Input:   None
+ * Output:  成功0,失败-1
+ */
+static int smtp_close_connection(void)
+{
+    int server_port_num = atoi(smtp_session.server_port);
+    if (server_port_num == 25)
+    {
+        return closesocket(smtp_session.conn_fd);
+    }
+#ifdef SMTP_CLIENT_USING_TLS
+    else if (server_port_num == 465 || server_port_num == 587)
+    {
+        return smtp_mbedtls_close_connection();
+    }
+#endif
+    else
+    {
+        return -1;
+    }
+}
+
+/**
+ * Name:    smtp_set_server_addr
+ * Brief:   设置邮箱服务器域名和端口
+ *          地址最大长度由 SMTP_MAX_ADDR_LEN 定义
+ * Input:
+ *  @server_addr: 服务器地址
+ *  @addr_type:   地址类型  
+ *                ADDR_TYPE_DOMAIN  域名类型
+ *                ADDR_TYPE_IP      IP地址类型
+ *  @port:        服务器端口
+ * Output:        0:设置成功,-1,:设置失败  
+ */
+int smtp_set_server_addr(const char *server_addr, uint8_t addr_type, const char *port)
+{
+    uint16_t addr_len = 0;
+    if (server_addr != NULL)
+    {
+        addr_len = strlen(server_addr);
+    }
+    else
+    {
+        SMTP_LOG("[smtp]: X  server addr is null!\r\n");
+        return -1;
+    }
+
+    if (addr_type == ADDRESS_TYPE_DOMAIN)
+    {
+        smtp_session.server_domain = server_addr;
+    }
+    else
+    {
+        if (addr_len > 15)
+        {
+            SMTP_LOG("[smtp]: X  server addr type error!\r\n");
+            return -1;
+        }
+        else
+        {
+            smtp_session.server_ip = server_addr;
+        }
+    }
+
+    if (strlen(port) <= 0)
+    {
+        SMTP_LOG("[smtp]: X  server port is null!\r\n");
+        return -1;
+    }
+    else
+    {
+        smtp_session.server_port = port;
+    }
+    return 0;
+}
+
+/**
+ * Name:    smtp_set_auth
+ * Brief:   设置连接smtp服务的用户名和密码
+ * Input:
+ *  @username:  用户名
+ *  @password:  密码
+ * Output:  设置成功:0,设置失败:-1
+ */
+int smtp_set_auth(const char *username, const char *password)
+{
+    uint32_t username_len = strlen(username);
+    uint32_t password_len = strlen(password);
+
+    if (!(username_len && password_len))
+    {
+        SMTP_LOG("[smtp]: X  username or password invalid!\r\n");
+        return -1;
+    }
+
+    if (smtp_base64_encode(smtp_session.username, SMTP_MAX_AUTH_LEN * 2, username, username_len) == 0)
+    {
+        SMTP_LOG("[smtp]: X  username encode error!\r\n");
+        return -1;
+    }
+
+    if (smtp_base64_encode(smtp_session.password, SMTP_MAX_AUTH_LEN * 2, password, password_len) == 0)
+    {
+        SMTP_LOG("[smtp]: X  password encode error!\r\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+/**
+ * Name:    smtp_connect_server_by_hostname
+ * Brief:   通过域名连接smtp服务器
+ * Input:   None
+ * Output:  成功0,失败-1
+ */
+static int smtp_connect_server_by_hostname(void)
+{
+    int result = -1;
+    char buf[3];
+    struct addrinfo hints, *addr_list, *cur;
+
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_family = AF_INET;
+    hints.ai_socktype = SOCK_STREAM;
+    hints.ai_protocol = IPPROTO_TCP;
+
+    if (getaddrinfo(smtp_session.server_domain, smtp_session.server_port, &hints, &addr_list) != 0)
+    {
+        SMTP_LOG("[smtp]: X  unknow server domain!\r\n");
+        return -1;
+    }
+
+    for (cur = addr_list; cur != NULL; cur = cur->ai_next)
+    {
+        smtp_session.conn_fd = (int)socket(cur->ai_family, cur->ai_socktype,
+                                           cur->ai_protocol);
+        if (smtp_session.conn_fd < 0)
+        {
+            result = -1;
+            continue;
+        }
+
+        if (connect(smtp_session.conn_fd, cur->ai_addr, (uint32_t)cur->ai_addrlen) == 0)
+        {
+            if (read(smtp_session.conn_fd, buf, 3) < 3)
+            {
+                SMTP_LOG("[smtp]: X  smtp server connect fail\r\n");
+                smtp_close_connection();
+                result = -1;
+                break;
+            }
+            else
+            {
+                if (memcmp(buf, "220", 3) == 0)
+                {
+                    SMTP_LOG("\r\n[smtp]: O  smtp server connect success!\r\n");
+                    SMTP_LOG("[smtp]: O  smtp server domain -> %s!\r\n", smtp_session.server_domain);
+                    result = 0;
+                    break;
+                }
+                else
+                {
+                    SMTP_LOG("[smtp]: X  smtp connection response check fail\r\n");
+                    smtp_close_connection();
+                    result = -1;
+                    break;
+                }
+            }
+        }
+        SMTP_LOG("[smtp]: X  smtp server connect fail\r\n");
+        smtp_close_connection();
+        result = -1;
+    }
+
+    freeaddrinfo(addr_list);
+    return result;
+}
+
+/**
+ * Name:    smtp_connect_server_by_ip
+ * Brief:   通过IP连接smtp服务器
+ * Input:   None
+ * Output:  成功0,失败-1
+ */
+static int smtp_connect_server_by_ip(void)
+{
+    int result = -1;
+
+    SMTP_LOG("[smtp]: X  current version don't support ip connect,please use server domain!\r\n");
+
+    return result;
+}
+
+/**
+ * Name:    smtp_flush
+ * Brief:   清空smtp数据读取区缓存
+ * Input:   None
+ * Output:  缓存中的数据个数,失败返回-1
+ */
+static int smtp_flush(void)
+{
+    int result = -1;
+    int server_port = atoi(smtp_session.server_port);
+    char buf[SMTP_RESPONSE_MAX_LEN];
+
+    while (1)
+    {
+        if (server_port == 25)
+        {
+            result = read(smtp_session.conn_fd, buf, SMTP_RESPONSE_MAX_LEN);
+        }
+#ifdef SMTP_CLIENT_USING_TLS
+        else if (server_port == 465)
+        {
+            result = smtp_mbedtls_client_read(smtp_session.tls_session, buf, SMTP_RESPONSE_MAX_LEN);
+        }
+        else if (server_port == 587)
+        {
+            if (smtp_session.state == SMTP_FINISH_START_TLS)
+            {
+                return 0;
+            }
+            else if (smtp_session.state < SMTP_AUTH_LOGIN)
+            {
+                result = read(smtp_session.conn_fd, buf, SMTP_RESPONSE_MAX_LEN);
+            }
+            else
+            {
+                result = smtp_mbedtls_client_read(smtp_session.tls_session, buf, SMTP_RESPONSE_MAX_LEN);
+            }
+        }
+#endif
+        else
+        {
+            SMTP_LOG("[smtp]: X  smtp flush port invalid \r\n");
+            return -1;
+        }
+
+        if (result <= 0)
+        {
+            SMTP_LOG("[smtp]: X  smtp net connection flush fail\r\n");
+            return -1;
+        }
+        return result;
+    }
+}
+
+/**
+ * Name:    smtp_write
+ * Brief:   根据不同的状态调用对应的write
+ * Input:
+ *  @buf:   要写入的数据
+ * Output:  成功写入的个数,错误返回-1
+ */
+static int smtp_write(char *buf)
+{
+    int server_port_num = atoi(smtp_session.server_port);
+    if (server_port_num == 25)
+    {
+        return write(smtp_session.conn_fd, buf, strlen(buf));
+    }
+#ifdef SMTP_CLIENT_USING_TLS
+    else if (server_port_num == 465)
+    {
+        return smtp_mbedtls_client_write(smtp_session.tls_session, buf);
+    }
+    else if (server_port_num == 587)
+    {
+        if (smtp_session.state < SMTP_FINISH_START_TLS)
+        {
+            return write(smtp_session.conn_fd, buf, strlen(buf));
+        }
+        else
+        {
+            return smtp_mbedtls_client_write(smtp_session.tls_session, buf);
+        }
+    }
+#endif
+    else
+    {
+        return -1;
+    }
+}
+
+/**
+ * Name:    smtp_read
+ * Brief:   根据不同的状态调用对应的read
+ * Input:
+ *  @buf:   读取数据的存储区
+ *  @nbyte: 准备读取数据的长度
+ * Output:  成功读取的个数,错误返回-1
+ */
+static int smtp_read(void *buf, size_t nbyte)
+{
+    int server_port_num = atoi(smtp_session.server_port);
+    if (server_port_num == 25)
+    {
+        return read(smtp_session.conn_fd, buf, nbyte);
+    }
+#ifdef SMTP_CLIENT_USING_TLS
+    else if (server_port_num == 465)
+    {
+        return smtp_mbedtls_client_read(smtp_session.tls_session, buf, nbyte);
+    }
+    else if (server_port_num == 587)
+    {
+        if (smtp_session.state < SMTP_FINISH_START_TLS)
+        {
+            return read(smtp_session.conn_fd, buf, nbyte);
+        }
+        else
+        {
+            return smtp_mbedtls_client_read(smtp_session.tls_session, buf, nbyte);
+        }
+    }
+#endif
+    else
+    {
+        return -1;
+    }
+}
+
+/**
+ * Name:    smtp_connect_server
+ * Brief:   smtp连接服务器
+ * Input:   None
+ * Output:  成功0,失败-1
+ */
+static int smtp_connect_server(void)
+{
+    int server_port_num = atoi(smtp_session.server_port);
+    if (server_port_num == 25)
+    {
+        if (smtp_session.server_ip)
+        {
+            return smtp_connect_server_by_ip();
+        }
+        else if (smtp_session.server_domain)
+        {
+            return smtp_connect_server_by_hostname();
+        }
+        else
+        {
+            SMTP_LOG("[smtp]: X  cannot find ip and domain\r\n");
+            return -1;
+        }
+    }
+#ifdef SMTP_CLIENT_USING_TLS
+    else if (server_port_num == 465)
+    {
+        return smtp_connect_server_by_tls();
+    }
+    else if (server_port_num == 587)
+    {
+        return smtp_connect_server_by_starttls();
+    }
+#endif
+    else
+    {
+        SMTP_LOG("[smtp]: X  invalid port number!\r\n");
+        return -1;
+    }
+}
+
+/**
+ * Name:    smtp_send_data_with_response_check
+ * Brief:   smtp数据发送并校验响应
+ * Input:   
+ *  @buf:   待发送的数据
+ *  @response_code: 正确响应码
+ * Output:  成功0,失败-1
+ */
+static int smtp_send_data_with_response_check(char *buf, char *response_code)
+{
+    char response_code_buf[3];
+    memset(response_code_buf, 0, 3);
+
+    if (smtp_session.conn_fd == 0
+#ifdef SMTP_CLIENT_USING_TLS
+        && smtp_session.tls_session == 0)
+#else
+    )
+#endif
+    {
+        SMTP_LOG("[smtp]: X  cannot find net fd\r\n");
+        return -1;
+    }
+    else
+    {
+        smtp_flush();
+        if (smtp_write(buf) != strlen(buf))
+        {
+            SMTP_LOG("[smtp]: X  smtp send fail\r\n");
+            smtp_close_connection();
+            return -1;
+        }
+        else
+        {
+            if (smtp_read(response_code_buf, 3) < 3)
+            {
+                SMTP_LOG("[smtp]: X  smtp read  response fail\r\n");
+                smtp_close_connection();
+                return -1;
+            }
+            if (memcmp(response_code, response_code_buf, 3) != 0)
+            {
+                SMTP_LOG("[smtp]: X  smtp check  response fail\r\n");
+                smtp_close_connection();
+                return -1;
+            }
+            else
+            {
+                return 0;
+            }
+        }
+    }
+}
+
+/**
+ * Name:    smtp_handshake
+ * Brief:   smtp握手认证
+ * Input:   None
+ * Output:  成功0,失败-1
+ */
+static int smtp_handshake(void)
+{
+    int result = -1;
+    result = smtp_send_data_with_response_check(SMTP_CMD_EHLO, "250");
+    if (result != 0)
+    {
+        SMTP_LOG("[smtp]: X  smtp helo fail\r\n");
+        return -1;
+    }
+
+#ifdef SMTP_CLIENT_USING_TLS
+    //STARTTLS
+    if (atoi(smtp_session.server_port) == 587)
+    {
+        smtp_session.state = SMTP_START_TLS;
+        if (smtp_send_data_with_response_check(SMTP_CMD_STARTTLS, "220") != 0)
+        {
+            SMTP_LOG("[smtp]: X  smtp start tls fail\r\n");
+            smtp_close_connection();
+            return -1;
+        }
+
+        smtp_flush();
+
+        if (smtp_mbedtls_starttls(smtp_session.tls_session) != 0)
+        {
+            SMTP_LOG("[smtp]: X  smtp start tls handshake fail\r\n");
+            return -1;
+        }
+        return 0;
+    }
+#endif
+    return result;
+}
+
+/**
+ * Name:    smtp_auth_login
+ * Brief:   smtp用户登录
+ * Input:   None
+ * Output:  成功0,失败-1
+ */
+static int smtp_auth_login(void)
+{
+    char auth_info_buf[SMTP_MAX_AUTH_LEN * 2 + 2];
+    memset(auth_info_buf, 0, SMTP_MAX_AUTH_LEN * 2 + 2);
+#ifdef SMTP_CLIENT_USING_TLS
+    if (atoi(smtp_session.server_port) == 587)
+    {
+        smtp_session.state = SMTP_FINISH_START_TLS;
+    }
+#endif
+    if (smtp_send_data_with_response_check(SMTP_CMD_AUTHLOGIN, "334") != 0)
+    {
+        SMTP_LOG("[smtp]: X  smtp auth login fail\r\n");
+        smtp_close_connection();
+        return -1;
+    }
+#ifdef SMTP_CLIENT_USING_TLS
+    if (atoi(smtp_session.server_port) == 587)
+    {
+        smtp_session.state = SMTP_AUTH_LOGIN;
+    }
+#endif
+    //发送用户名信息
+    sprintf(auth_info_buf, "%s\r\n", smtp_session.username);
+    if (smtp_send_data_with_response_check(auth_info_buf, "334") != 0)
+    {
+        SMTP_LOG("[smtp]: X  smtp send username fail\r\n");
+        smtp_close_connection();
+        return -1;
+    }
+    //发送密码信息
+    sprintf(auth_info_buf, "%s\r\n", smtp_session.password);
+    if (smtp_send_data_with_response_check(auth_info_buf, "235") != 0)
+    {
+        SMTP_LOG("[smtp]: X  smtp password invalid\r\n");
+        smtp_close_connection();
+        return -1;
+    }
+    return 0;
+}
+
+/**
+ * Name:    smtp_set_sender_receiver
+ * Brief:   smtp设置邮箱的发件人与收件人
+ * Input:   None
+ * Output:  发送成功0,发送失败-1
+ */
+static int smtp_set_sender_receiver(void)
+{
+    uint16_t mail_buf_len = SMTP_MAX_ADDR_LEN + strlen(SMTP_CMD_MAIL_HEAD) + strlen(SMTP_CMD_MAIL_END);
+    uint16_t rcpt_buf_len = SMTP_MAX_ADDR_LEN + strlen(SMTP_CMD_RCPT_HEAD) + strlen(SMTP_CMD_RCPT_END);
+    //使用较大的长度
+    uint16_t buf_len = (mail_buf_len > rcpt_buf_len) ? mail_buf_len : rcpt_buf_len;
+
+    char addr_info_buf[buf_len];
+    memset(addr_info_buf, 0, buf_len);
+
+    sprintf(addr_info_buf, "%s%s%s", SMTP_CMD_MAIL_HEAD, smtp_session.address_from, SMTP_CMD_MAIL_END);
+    if (smtp_send_data_with_response_check(addr_info_buf, "250") != 0)
+    {
+        SMTP_LOG("[smtp]: X  smtp set mail from fail\r\n");
+        smtp_close_connection();
+        return -1;
+    }
+
+    sprintf(addr_info_buf, "%s%s%s", SMTP_CMD_RCPT_HEAD, smtp_session.address_to, SMTP_CMD_RCPT_END);
+    if (smtp_send_data_with_response_check(addr_info_buf, "250") != 0)
+    {
+        SMTP_LOG("[smtp]: X  smtp set rcpt to fail\r\n");
+        smtp_close_connection();
+        return -1;
+    }
+    return 0;
+}
+
+/**
+ * Name:    smtp_send_content
+ * Brief:   smtp发送邮件内容
+ * Input:   None
+ * Output:  发送成功0,发送失败-1
+ */
+static int smtp_send_content(void)
+{
+    char content_buf[SMTP_SEND_DATA_HEAD_MAX_LENGTH + SMTP_SEND_DATA_MAX_LEN];
+    memset(content_buf, 0, SMTP_SEND_DATA_HEAD_MAX_LENGTH + SMTP_SEND_DATA_MAX_LEN);
+
+    if (smtp_send_data_with_response_check(SMTP_CMD_DATA, "354") != 0)
+    {
+        SMTP_LOG("[smtp]: X  smtp send data cmd fail\r\n");
+        smtp_close_connection();
+        return -1;
+    }
+    //拼接内容
+    sprintf(content_buf, "FROM: <%s>\r\nTO: <%s>\r\nSUBJECT:%s\r\n\r\n%s\r\n.\r\n",
+            smtp_session.address_from, smtp_session.address_to, smtp_session.subject, smtp_session.body);
+
+    if (smtp_send_data_with_response_check(content_buf, "250") != 0)
+    {
+        SMTP_LOG("[smtp]: X  smtp send data content fail\r\n");
+        smtp_close_connection();
+        return -1;
+    }
+
+    return 0;
+}
+
+/**
+ * Name:    smtp_quit
+ * Brief:   smtp 结束一次完整的通信
+ * Input:   None
+ * Output:  成功0,失败-1
+ */
+static int smtp_quit(void)
+{
+    if (smtp_send_data_with_response_check(SMTP_CMD_QUIT, "221") != 0)
+    {
+        SMTP_LOG("[smtp]: X  smtp quit fail\r\n");
+        smtp_close_connection();
+        return -1;
+    }
+    SMTP_LOG("[smtp]: O  smtp mail send sussess!\r\n");
+    //关闭连接
+    smtp_close_connection();
+    SMTP_LOG("[smtp]: O  close smtp connection!\r\n");
+    return 0;
+}
+
+/**
+ * Name:    smtp_send
+ * Brief:   真实的发送函数
+ * Input:   
+ *  @port_num:  发送邮件的端口号字符串
+ * Output:  发送成功0,发送失败-1
+ */
+static int smtp_send(void)
+{
+    //连接服务器
+    smtp_session.state = SMTP_NULL;
+    if (smtp_connect_server() != 0)
+    {
+        return -1;
+    }
+    //握手确认
+    smtp_session.state = SMTP_HELO;
+    if (smtp_handshake() != 0)
+    {
+        return -1;
+    }
+    //用户认证
+    smtp_session.state = SMTP_AUTH_LOGIN;
+    if (smtp_auth_login() != 0)
+    {
+        return -1;
+    }
+    //设置发件人与收件人
+    smtp_session.state = SMTP_MAIL;
+    if (smtp_set_sender_receiver() != 0)
+    {
+        return -1;
+    }
+    //发送数据
+    smtp_session.state = SMTP_DATA;
+    if (smtp_send_content() != 0)
+    {
+        return -1;
+    }
+    //结束
+    smtp_session.state = SMTP_QUIT;
+    if (smtp_quit() != 0)
+    {
+        return -1;
+    }
+    return 0;
+}
+
+/**
+ * Name:    smtp_send_mail
+ * Brief:   smtp邮件发送
+ * Input:
+ *  @from:     发送者邮箱
+ *  @to:       接受者邮箱
+ *  @subject:  主题
+ *  @body:     内容
+ * Output:  成功0,失败-1
+ */
+int smtp_send_mail(char *from, char *to, char *subject, char *body)
+{
+    if (strlen(from) > SMTP_MAX_ADDR_LEN)
+    {
+        SMTP_LOG("[smtp]: X  sender address is too long!\r\n");
+        return -1;
+    }
+    else
+    {
+        smtp_session.address_from = from;
+    }
+
+    if (strlen(to) > SMTP_MAX_ADDR_LEN)
+    {
+        SMTP_LOG("[smtp]: X  receiver address is too long!\r\n");
+        return -1;
+    }
+    else
+    {
+        smtp_session.address_to = to;
+    }
+
+    if (subject == NULL)
+    {
+        SMTP_LOG("[smtp]: X subject is null!\r\n");
+        return -1;
+    }
+    else
+    {
+        smtp_session.subject = subject;
+    }
+
+    if (body == NULL)
+    {
+        SMTP_LOG("[smtp]: X body is null!\r\n");
+        return -1;
+    }
+    else
+    {
+        smtp_session.body = body;
+    }
+
+    //调用真实的发送函数
+    return smtp_send();
+}

+ 76 - 0
src/smtp_client_data.c

@@ -0,0 +1,76 @@
+/*************************************************
+ Copyright (c) 2019
+ All rights reserved.
+ File name:     smtp_client_data.c
+ Description:   smtp 数据处理源文件
+ History:
+ 1. Version:    
+    Date:       2019-10-10
+    Author:     wangjunjie
+    Modify:     
+*************************************************/
+
+#include <stdint.h>
+#include "smtp_client_private.h"
+
+const uint8_t smtp_base64_table[] = {
+    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
+    'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+    'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+    'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
+    'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
+    'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+    '+', '/'};
+
+/**
+ * Name:    smtp_base64_encode
+ * Brief:   base64加密
+ * Input:
+ *  @target:加密数据存储位置
+ *  @target_len:存储区的长度
+ *  @source:原始数据
+ *  @source_len:原始数据长度
+ * Output:  加密后数据的长度,出错返回0
+ */
+uint32_t
+smtp_base64_encode(char *target, uint32_t target_len, const char *source, uint32_t source_len)
+{
+    uint32_t i;
+    int8_t j;
+    uint32_t target_idx = 0;
+    uint32_t longer = (3 - (source_len % 3) == 3) ? 0 : (3 - (source_len % 3));
+    uint32_t source_len_b64 = source_len + longer;
+    uint32_t len = (((source_len_b64)*4) / 3);
+    uint8_t x = 5;
+    uint8_t current = 0;
+
+    if (target_len < len)
+    {
+        SMTP_LOG("[smtp]: X  target_len is too short\r\n");
+        return 0;
+    }
+
+    for (i = 0; i < source_len_b64; i++)
+    {
+        uint8_t b = (i < source_len ? source[i] : 0);
+        for (j = 7; j >= 0; j--, x--)
+        {
+            uint8_t shift = ((b & (1 << j)) != 0) ? 1 : 0;
+            current |= shift << x;
+            if (x == 0)
+            {
+                target[target_idx++] = smtp_base64_table[current];
+                x = 6;
+                current = 0;
+            }
+        }
+    }
+
+    for (i = len - longer; i < len; i++)
+    {
+        target[i] = '=';
+    }
+
+    return len;
+}

+ 344 - 0
src/smtp_client_tls.c

@@ -0,0 +1,344 @@
+/*************************************************
+ Copyright (c) 2019
+ All rights reserved.
+ File name:     smtp_client_tls.c
+ Description:   
+ History:
+ 1. Version:    
+    Date:       2019-10-12
+    Author:     wangjunjie
+    Modify:     
+*************************************************/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <rtthread.h>
+
+#include "smtp_client_private.h"
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include <mbedtls/config.h>
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+/**
+ * Name:    smtp_mbedtls_context_create
+ * Brief:   创建smtp加密环境
+ * Input:
+ *  @smtp_session:  smtp会话
+ * Output:  成功返回tls会话,失败返回NULL并释放tls资源
+ */
+static MbedTLSSession *smtp_mbedtls_context_create(smtp_session_t *smtp_session)
+{
+    MbedTLSSession *tls_session = RT_NULL;
+
+    tls_session = (MbedTLSSession *)tls_malloc(sizeof(MbedTLSSession));
+    if (tls_session == RT_NULL)
+    {
+        SMTP_LOG("[smtp]: X  No memory for MbedTLS session object.\r\n");
+        return NULL;
+    }
+    rt_memset(tls_session, 0x0, sizeof(MbedTLSSession));
+
+    //拷贝服务器地址
+    if (smtp_session->server_ip)
+    {
+        tls_session->host = tls_strdup(smtp_session->server_ip);
+    }
+    else if (smtp_session->server_domain)
+    {
+        tls_session->host = tls_strdup(smtp_session->server_domain);
+    }
+    else
+    {
+        SMTP_LOG("[smtp]: X  cannot find server ip or domain\r\n");
+        tls_free(tls_session);
+        return NULL;
+    }
+    //拷贝服务器端口
+    if (smtp_session->server_port)
+    {
+        tls_session->port = tls_strdup(smtp_session->server_port);
+    }
+    else
+    {
+        SMTP_LOG("[smtp]: X  cannot find server port\r\n");
+        if (tls_session->host)
+        {
+            tls_free(tls_session->host);
+        }
+        tls_free(tls_session);
+        return NULL;
+    }
+    //分配数据接收缓冲区
+    tls_session->buffer_len = MBEDTLS_READ_BUFFER_LEN;
+    tls_session->buffer = tls_malloc(tls_session->buffer_len);
+    memset(tls_session->buffer, 0, MBEDTLS_READ_BUFFER_LEN);
+    if (tls_session->buffer == RT_NULL)
+    {
+        SMTP_LOG("[smtp]: X  no memory for MbedTLS buffer\r\n");
+        if (tls_session->host)
+        {
+            tls_free(tls_session->host);
+        }
+        if (tls_session->port)
+        {
+            tls_free(tls_session->port);
+        }
+        tls_free(tls_session);
+        return NULL;
+    }
+    return tls_session;
+}
+
+/**
+ * Name:    smtp_mbedtls_client_init
+ * Brief:   初始化 TLS 客户端
+ * Input:
+ *  @smtp_session:  smtp会话
+ * Output:  成功返回0,失败返回-1并关闭tls连接
+ */
+static int smtp_mbedtls_client_init(MbedTLSSession *tls_session)
+{
+    //设置随机字符串种子
+    char *pers = "hello_smtp";
+    int result = -1;
+
+    if ((result = mbedtls_client_init(tls_session, (void *)pers, strlen(pers))) != 0)
+    {
+        SMTP_LOG("[smtp]: X  MbedTLSClientInit err return : -0x%x\n", -result);
+        mbedtls_client_close(tls_session);
+        SMTP_LOG("[smtp]: O  MbedTLS connection close\n");
+        return -1;
+    }
+    return result;
+}
+
+/**
+ * Name:    smtp_mbedtls_client_context
+ * Brief:   初始化 SSL/TLS 客户端上下文
+ * Input:
+ *  @smtp_session:  smtp会话
+ * Output:  成功返回0,失败返回-1并关闭tls连接
+ */
+static int smtp_mbedtls_client_context(MbedTLSSession *tls_session)
+{
+    int result = -1;
+    if ((result = mbedtls_client_context(tls_session)) < 0)
+    {
+        SMTP_LOG("[smtp]: X  MbedTLSCLlientContext  err return : -0x%x\n", -result);
+        mbedtls_client_close(tls_session);
+        SMTP_LOG("[smtp]: O  MbedTLS connection close\n");
+        return -1;
+    }
+    return result;
+}
+
+/**
+ * Name:    smtp_mbedtls_client_connect
+ * Brief:   建立 SSL/TLS 连接
+ * Input:
+ *  @smtp_session:  smtp会话
+ * Output:  成功返回0,失败返回-1并关闭tls连接
+ */
+static int smtp_mbedtls_client_connect(MbedTLSSession *tls_session)
+{
+    int result = -1;
+    if ((result = mbedtls_client_connect(tls_session)) != 0)
+    {
+        SMTP_LOG("[smtp]: X  MbedTLSCLlientConnect   err return : -0x%x\n", -result);
+        mbedtls_client_close(tls_session);
+        SMTP_LOG("[smtp]: O  MbedTLS connection close\n");
+        return -1;
+    }
+    return result;
+}
+
+/**
+ * Name:    smtp_mbedtls_client_write
+ * Brief:   向SSL/TLS中写入数据
+ * Input:
+ *  @smtp_session:  smtp会话
+ *  @buf:           写入的字符串
+ * Output:  成功写入的字符个数,失败返回-1或0并关闭tls连接
+ */
+int smtp_mbedtls_client_write(MbedTLSSession *tls_session, char *buf)
+{
+    int result = -1;
+    while ((result = mbedtls_client_write(tls_session, (const unsigned char *)buf, strlen(buf))) <= 0)
+    {
+        if (result != MBEDTLS_ERR_SSL_WANT_READ && result != MBEDTLS_ERR_SSL_WANT_WRITE)
+        {
+            SMTP_LOG("[smtp]: X  mbedtls_ssl_write  err return : -0x%x\n", -result);
+            return -1;
+        }
+    }
+    return result;
+}
+
+/**
+ * Name:    smtp_mbedtls_client_read
+ * Brief:   从 SSL/TLS 中读取数据
+ * Input:
+ *  @smtp_session:  smtp会话
+ * Output:  成功读取的字符个数,失败返回-1并关闭tls连接
+ */
+int smtp_mbedtls_client_read(MbedTLSSession *tls_session, char *buf, size_t len)
+{
+    int result = -1;
+    memset(buf, 0x00, len);
+    result = mbedtls_client_read(tls_session, (unsigned char *)buf, len);
+    if (result < 0)
+    {
+        SMTP_LOG("[smtp]: X  mbedtls_ssl_read returned -0x%x\n", -result);
+    }
+    if (result == 0)
+    {
+        SMTP_LOG("[smtp]: X  connection closed\n");
+    }
+    return result;
+}
+
+/**
+ * Name:    smtp_mbedtls_starttls
+ * Brief:   开启starttls
+ * Input:
+ *  @tls_session:   smtp会话
+ * Output:  成功返回0,失败返回-1并关闭连接
+ */
+int smtp_mbedtls_starttls(MbedTLSSession *tls_session)
+{
+    int result = -1;
+    //设置网络操作接口
+    mbedtls_ssl_set_bio(&tls_session->ssl, &tls_session->server_fd, mbedtls_net_send, mbedtls_net_recv, NULL);
+    //TLS握手
+    while ((result = mbedtls_ssl_handshake(&tls_session->ssl)) != 0)
+    {
+        if (result != MBEDTLS_ERR_SSL_WANT_READ && result != MBEDTLS_ERR_SSL_WANT_WRITE)
+        {
+            SMTP_LOG("[smtp]: X  smtp mbedtls handshake fail\n");
+            mbedtls_client_close(tls_session);
+            SMTP_LOG("[smtp]: O  MbedTLS connection close\n");
+            return -1;
+        }
+    }
+    //证书验证
+    result = mbedtls_ssl_get_verify_result(&tls_session->ssl);
+    if (result != 0)
+    {
+        memset(tls_session->buffer, 0x00, tls_session->buffer_len);
+        mbedtls_x509_crt_verify_info((char *)tls_session->buffer, tls_session->buffer_len, "  ! ", result);
+        SMTP_LOG("[smtp]: X  smtp mbedtls crt verify fail\n");
+        mbedtls_client_close(tls_session);
+        SMTP_LOG("[smtp]: O  MbedTLS connection close\n");
+        return -1;
+    }
+    return result;
+}
+
+/**
+ * Name:    smtp_connect_server_by_tls
+ * Brief:   smtp 以tls加密方式连接服务器
+ * Input:   None
+ * Output:  成功返回0,失败返回-1
+ */
+int smtp_connect_server_by_tls(void)
+{
+    int result = -1;
+    //初始化TLS会话
+    smtp_session.tls_session = smtp_mbedtls_context_create(&smtp_session);
+    if (smtp_session.tls_session == NULL)
+    {
+        return -1;
+    }
+    //初始化TLS/SSL客户端
+    result = smtp_mbedtls_client_init(smtp_session.tls_session);
+    if (result != 0)
+    {
+        return -1;
+    }
+    //初始化 SSL/TLS 客户端上下文
+    result = smtp_mbedtls_client_context(smtp_session.tls_session);
+    if (result != 0)
+    {
+        return -1;
+    }
+    //建立ssl连接
+    result = smtp_mbedtls_client_connect(smtp_session.tls_session);
+    if (result != 0)
+    {
+        return -1;
+    }
+    smtp_session.conn_fd = smtp_session.tls_session->server_fd.fd;
+    return result;
+}
+
+/**
+ * Name:    smtp_connect_server_by_starttls
+ * Brief:   smtp mbedtls 网络连接(用于starttls方式)
+ * Input:   None
+ * Output:  成功返回0,失败返回-1并释放资源
+ */
+int smtp_connect_server_by_starttls(void)
+{
+    int result = -1;
+    //初始化TLS会话
+    smtp_session.tls_session = smtp_mbedtls_context_create(&smtp_session);
+    if (smtp_session.tls_session == NULL)
+    {
+        return -1;
+    }
+    //初始化TLS/SSL客户端
+    result = smtp_mbedtls_client_init(smtp_session.tls_session);
+    if (result != 0)
+    {
+        return -1;
+    }
+    //初始化 SSL/TLS 客户端上下文
+    result = smtp_mbedtls_client_context(smtp_session.tls_session);
+    if (result != 0)
+    {
+        return -1;
+    }
+
+    result = mbedtls_net_connect(&smtp_session.tls_session->server_fd, smtp_session.tls_session->host,
+                                 smtp_session.tls_session->port, MBEDTLS_NET_PROTO_TCP);
+
+    if (result != 0)
+    {
+        SMTP_LOG("[smtp]: X  smtp mbedtls net connect fail\n");
+        mbedtls_client_close(smtp_session.tls_session);
+    }
+    smtp_session.conn_fd = smtp_session.tls_session->server_fd.fd;
+    return result;
+}
+
+/**
+ * Name:    smtp_mbedtls_close_connection
+ * Brief:   smtp 关闭tls连接,释放资源
+ * Input:   None
+ * Output:  成功返回0,失败返回-1
+ */
+int smtp_mbedtls_close_connection(void)
+{
+    int result = -1;
+    if (smtp_session.tls_session)
+    {
+        result = mbedtls_client_close(smtp_session.tls_session);
+        if (result == 0)
+        {
+            smtp_session.tls_session = NULL;
+        }
+        else
+        {
+            SMTP_LOG("[smtp]: X  smtp tls session free fail!\r\n");
+        }
+        return result;
+    }
+    else
+    {
+        return 0;
+    }
+}