diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..9fd7fa1
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,17 @@
+# EditorConfig root file
+root = true
+
+# Unix-style newlines with a newline ending every file
+[*]
+charset = utf-8
+end_of_line = lf
+indent_size = 4
+indent_style = space
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+[{*.robot}]
+indent_size = 2
+
+[*.rst]
+trim_trailing_whitespace = false
diff --git a/.gitignore b/.gitignore
index 09bf34c..016e412 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,30 +1,7 @@
-*.py[co]
-
-# Packages
-*.egg
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
*.egg-info
-dist
-build
-eggs
-parts
-bin
-var
-sdist
-develop-eggs
-.installed.cfg
-
-# Installer logs
-pip-log.txt
-
-# Unit test / coverage reports
.coverage
-.tox
-
-#Translations
-*.mo
-
-#Mr Developer
-.mr.developer.cfg
-
-#vim
-*.swp
+dist
+htmlcov
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
new file mode 100644
index 0000000..287920e
--- /dev/null
+++ b/CHANGELOG.rst
@@ -0,0 +1,72 @@
+0.2.0 (2015.12.15)
+==================
+
+* Transition from previous project maintainer
+* Follow Python code style guide
+* Initial project infrastructure
+
+0.1.4 (2014.04.23)
+==================
+
+* Fix multipart-mime reading (thanks to Frank Berthold)
+
+0.1.3 (2014.02.28)
+==================
+
+* Fix Gmail search contributed by https://github.com/martinhill
+
+0.1.2 (2014.01.16)
+==================
+
+* Throw exception when IMAP server responds with error
+
+0.1.1 (2013.12.20)
+==================
+
+* Add multipart email capabilities
+
+0.1.0 (2012.12.21)
+==================
+
+* Add status filter to ``wait_for_mail`` keyword
+* Fix opened page encoding to ``open_link_from_mail`` keyword
+
+0.0.8 (2012.11.28)
+==================
+
+* Get email body - another attempt
+
+0.0.7 (2012.11.27)
+==================
+
+* Get email body
+
+0.0.6 (2012.11.27)
+==================
+
+* Mark emails as read
+
+0.0.5 (2012.09.25)
+==================
+
+* Add build environment and unit test
+
+0.0.4 (2012.09.13)
+==================
+
+* Add get links from email keyword
+
+0.0.3 (2012.08.20)
+==================
+
+* Documents and Apache license
+
+0.0.2 (2012.08.20)
+==================
+
+* from and to email are not required
+
+0.0.1 (2012.08.20)
+==================
+
+* Initial version
diff --git a/CHANGES.txt b/CHANGES.txt
deleted file mode 100644
index d67478b..0000000
--- a/CHANGES.txt
+++ /dev/null
@@ -1,72 +0,0 @@
-======================================
-Changes for robotframework-imaplibrary
-======================================
-
-2014/04/23 0.1.4
-================
-
- - Fixed multipart-mime reading (thanks to Frank Berthold)
-
-2014/02/28 0.1.3
-================
-
- - fixed searching with gmail
- contributed by https://github.com/martinhill
-
-2014/01/16 0.1.2
-================
-
- - throw exception when IMAP server responds with error
-
-2013/12/20 0.1.1
-=================
-
- - added multipart email capabilities
-
-2012/12/21 0.1.0
-================
-
- - added filter for status to 'wait_for_mail'
-
- - bugfix: use encoding from opened page while 'open_link_from_mail'
-
-2012/11/28 0.0.8
-================
-
- - get email body
-
-
-2012/11/27 0.0.7
-================
-
- - get email body
-
-2012/11/27 0.0.6
-================
-
- - mark mails as read
-
-2012/09/25 0.0.5
-================
-
- - added buildout environment and unit test
-
-2012/09/13 0.0.4
-================
-
- - added get links from email keyword
-
-2012/08/20 0.0.3
-================
-
- - docs and apache license
-
-2012/08/20 0.0.2
-================
-
- - from and to email not required
-
-2012/08/20 0.0.1
-================
-
- - initial version
diff --git a/COPYRIGHT.rst b/COPYRIGHT.rst
new file mode 100644
index 0000000..a780185
--- /dev/null
+++ b/COPYRIGHT.rst
@@ -0,0 +1 @@
+# Copyright 2015 Richard Huang
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..37ec93a
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,191 @@
+Apache License
+Version 2.0, January 2004
+http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+"License" shall mean the terms and conditions for use, reproduction, and
+distribution as defined by Sections 1 through 9 of this document.
+
+"Licensor" shall mean the copyright owner or entity authorized by the copyright
+owner that is granting the License.
+
+"Legal Entity" shall mean the union of the acting entity and all other entities
+that control, are controlled by, or are under common control with that entity.
+For the purposes of this definition, "control" means (i) the power, direct or
+indirect, to cause the direction or management of such entity, whether by
+contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
+outstanding shares, or (iii) beneficial ownership of such entity.
+
+"You" (or "Your") shall mean an individual or Legal Entity exercising
+permissions granted by this License.
+
+"Source" form shall mean the preferred form for making modifications, including
+but not limited to software source code, documentation source, and configuration
+files.
+
+"Object" form shall mean any form resulting from mechanical transformation or
+translation of a Source form, including but not limited to compiled object code,
+generated documentation, and conversions to other media types.
+
+"Work" shall mean the work of authorship, whether in Source or Object form, made
+available under the License, as indicated by a copyright notice that is included
+in or attached to the work (an example is provided in the Appendix below).
+
+"Derivative Works" shall mean any work, whether in Source or Object form, that
+is based on (or derived from) the Work and for which the editorial revisions,
+annotations, elaborations, or other modifications represent, as a whole, an
+original work of authorship. For the purposes of this License, Derivative Works
+shall not include works that remain separable from, or merely link (or bind by
+name) to the interfaces of, the Work and Derivative Works thereof.
+
+"Contribution" shall mean any work of authorship, including the original version
+of the Work and any modifications or additions to that Work or Derivative Works
+thereof, that is intentionally submitted to Licensor for inclusion in the Work
+by the copyright owner or by an individual or Legal Entity authorized to submit
+on behalf of the copyright owner. For the purposes of this definition,
+"submitted" means any form of electronic, verbal, or written communication sent
+to the Licensor or its representatives, including but not limited to
+communication on electronic mailing lists, source code control systems, and
+issue tracking systems that are managed by, or on behalf of, the Licensor for
+the purpose of discussing and improving the Work, but excluding communication
+that is conspicuously marked or otherwise designated in writing by the copyright
+owner as "Not a Contribution."
+
+"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
+of whom a Contribution has been received by Licensor and subsequently
+incorporated within the Work.
+
+2. Grant of Copyright License.
+
+Subject to the terms and conditions of this License, each Contributor hereby
+grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
+irrevocable copyright license to reproduce, prepare Derivative Works of,
+publicly display, publicly perform, sublicense, and distribute the Work and such
+Derivative Works in Source or Object form.
+
+3. Grant of Patent License.
+
+Subject to the terms and conditions of this License, each Contributor hereby
+grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
+irrevocable (except as stated in this section) patent license to make, have
+made, use, offer to sell, sell, import, and otherwise transfer the Work, where
+such license applies only to those patent claims licensable by such Contributor
+that are necessarily infringed by their Contribution(s) alone or by combination
+of their Contribution(s) with the Work to which such Contribution(s) was
+submitted. If You institute patent litigation against any entity (including a
+cross-claim or counterclaim in a lawsuit) alleging that the Work or a
+Contribution incorporated within the Work constitutes direct or contributory
+patent infringement, then any patent licenses granted to You under this License
+for that Work shall terminate as of the date such litigation is filed.
+
+4. Redistribution.
+
+You may reproduce and distribute copies of the Work or Derivative Works thereof
+in any medium, with or without modifications, and in Source or Object form,
+provided that You meet the following conditions:
+
+You must give any other recipients of the Work or Derivative Works a copy of
+this License; and
+You must cause any modified files to carry prominent notices stating that You
+changed the files; and
+You must retain, in the Source form of any Derivative Works that You distribute,
+all copyright, patent, trademark, and attribution notices from the Source form
+of the Work, excluding those notices that do not pertain to any part of the
+Derivative Works; and
+If the Work includes a "NOTICE" text file as part of its distribution, then any
+Derivative Works that You distribute must include a readable copy of the
+attribution notices contained within such NOTICE file, excluding those notices
+that do not pertain to any part of the Derivative Works, in at least one of the
+following places: within a NOTICE text file distributed as part of the
+Derivative Works; within the Source form or documentation, if provided along
+with the Derivative Works; or, within a display generated by the Derivative
+Works, if and wherever such third-party notices normally appear. The contents of
+the NOTICE file are for informational purposes only and do not modify the
+License. You may add Your own attribution notices within Derivative Works that
+You distribute, alongside or as an addendum to the NOTICE text from the Work,
+provided that such additional attribution notices cannot be construed as
+modifying the License.
+You may add Your own copyright statement to Your modifications and may provide
+additional or different license terms and conditions for use, reproduction, or
+distribution of Your modifications, or for any such Derivative Works as a whole,
+provided Your use, reproduction, and distribution of the Work otherwise complies
+with the conditions stated in this License.
+
+5. Submission of Contributions.
+
+Unless You explicitly state otherwise, any Contribution intentionally submitted
+for inclusion in the Work by You to the Licensor shall be under the terms and
+conditions of this License, without any additional terms or conditions.
+Notwithstanding the above, nothing herein shall supersede or modify the terms of
+any separate license agreement you may have executed with Licensor regarding
+such Contributions.
+
+6. Trademarks.
+
+This License does not grant permission to use the trade names, trademarks,
+service marks, or product names of the Licensor, except as required for
+reasonable and customary use in describing the origin of the Work and
+reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty.
+
+Unless required by applicable law or agreed to in writing, Licensor provides the
+Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+including, without limitation, any warranties or conditions of TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
+solely responsible for determining the appropriateness of using or
+redistributing the Work and assume any risks associated with Your exercise of
+permissions under this License.
+
+8. Limitation of Liability.
+
+In no event and under no legal theory, whether in tort (including negligence),
+contract, or otherwise, unless required by applicable law (such as deliberate
+and grossly negligent acts) or agreed to in writing, shall any Contributor be
+liable to You for damages, including any direct, indirect, special, incidental,
+or consequential damages of any character arising as a result of this License or
+out of the use or inability to use the Work (including but not limited to
+damages for loss of goodwill, work stoppage, computer failure or malfunction, or
+any and all other commercial damages or losses), even if such Contributor has
+been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability.
+
+While redistributing the Work or Derivative Works thereof, You may choose to
+offer, and charge a fee for, acceptance of support, warranty, indemnity, or
+other liability obligations and/or rights consistent with this License. However,
+in accepting such obligations, You may act only on Your own behalf and on Your
+sole responsibility, not on behalf of any other Contributor, and only if You
+agree to indemnify, defend, and hold each Contributor harmless for any liability
+incurred by, or claims asserted against, such Contributor by reason of your
+accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work
+
+To apply the Apache License to your work, attach the following boilerplate
+notice, with the fields enclosed by brackets "[]" replaced with your own
+identifying information. (Don't include the brackets!) The text should be
+enclosed in the appropriate comment syntax for the file format. We also
+recommend that a file or class name and description of purpose be included on
+the same "printed page" as the copyright notice for easier identification within
+third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/MANIFEST b/MANIFEST
deleted file mode 100644
index 6708f9f..0000000
--- a/MANIFEST
+++ /dev/null
@@ -1,6 +0,0 @@
-# file GENERATED by distutils, do NOT edit
-README.rst
-setup.py
-src/ImapLibrary/__init__.py
-src/ImapLibrary/tests.py
-src/ImapLibrary/version.py
diff --git a/MANIFEST.in b/MANIFEST.in
index 9561fb1..af87ba1 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1 +1,3 @@
-include README.rst
+include *.rst LICENSE
+recursive-include doc *.html
+recursive-include src *.py
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..dc7f11a
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,66 @@
+# Copyright 2015 Richard Huang
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LIBRARY_NAME = ImapLibrary
+
+lc = $(subst A,a,$(subst B,b,$(subst C,c,$(subst D,d,$(subst E,e,$(subst F,f,$(subst G,g,$(subst H,h,$(subst I,i,$(subst J,j,$(subst K,k,$(subst L,l,$(subst M,m,$(subst N,n,$(subst O,o,$(subst P,p,$(subst Q,q,$(subst R,r,$(subst S,s,$(subst T,t,$(subst U,u,$(subst V,v,$(subst W,w,$(subst X,x,$(subst Y,y,$(subst Z,z,$1))))))))))))))))))))))))))
+
+.PHONY: help test
+
+help:
+ @echo targets: clean, clean_dist, version, install_devel_deps, lint, test, doc, github_doc, testpypi, pypi
+
+clean:
+ python setup.py clean --all
+ rm -rf .coverage htmlcov src/*.egg-info
+ find . -iname "*.pyc" -delete
+ find . -iname "__pycache__" | xargs rm -rf {} \;
+
+clean_dist:
+ rm -rf dist
+
+version:
+ python -m robot.libdoc src/$(LIBRARY_NAME) version
+
+install_devel_deps:
+ pip install -e .
+ pip install coverage mock
+
+lint:clean
+ flake8 --max-complexity 10
+ pylint --rcfile=setup.cfg src/$(LIBRARY_NAME)/*.py
+
+test:clean
+ PYTHONPATH=./src: coverage run --source=src -m unittest discover test/utest
+ coverage report
+
+doc:clean
+ python -m robot.libdoc src/$(LIBRARY_NAME) doc/$(LIBRARY_NAME).html
+ python -m analytics doc/$(LIBRARY_NAME).html
+
+github_doc:clean
+ git checkout gh-pages
+ git merge master
+ git push origin gh-pages
+ git checkout master
+
+testpypi:clean_dist doc
+ python setup.py register -r test
+ python setup.py sdist upload -r test --sign
+ @echo https://testpypi.python.org/pypi/robotframework-$(call lc,$(LIBRARY_NAME))/
+
+pypi:clean_dist doc
+ python setup.py register -r pypi
+ python setup.py sdist upload -r pypi --sign
+ @echo https://pypi.python.org/pypi/robotframework-$(call lc,$(LIBRARY_NAME))/
diff --git a/README b/README
new file mode 120000
index 0000000..92cacd2
--- /dev/null
+++ b/README
@@ -0,0 +1 @@
+README.rst
\ No newline at end of file
diff --git a/README.rst b/README.rst
index e4f10da..fe89e1b 100644
--- a/README.rst
+++ b/README.rst
@@ -1,161 +1,247 @@
-==========================
-robotframework-imaplibrary
-==========================
+IMAP email testing library for Robot Framework
+==============================================
+
+|Docs| |Version| |Status| |Python| |Download| |License|
+
+Introduction
+------------
+
+ImapLibrary is a IMAP email testing library for `Robot Framework`_.
+
+More information about this library can be found in the `Keyword Documentation`_.
+
+Non-Backward Compatible Warning
+-------------------------------
+There are inevitable changes to parameter names that would not be backward compatible with
+release 0.1.4 downwards.
+These changes are made to comply with Python code style guide on `Method Names and Instance Variables`_.
+
+Example
+'''''''
+
++----------------+----------------------------+-------------------------------+-----------------+
+| Open Mailbox | server=imap.googlemail.com | user=email@gmail.com | password=secret |
++----------------+----------------------------+-------------------------------+-----------------+
+| ${LATEST} = | Wait For Mail | from_email=noreply@domain.com | timeout=300 |
++----------------+----------------------------+-------------------------------+-----------------+
+| ${HTML} = | Open Link From Mail | ${LATEST} |
++----------------+----------------------------+-------------------------------------------------+
+| Should Contain | ${HTML} | Your email address has been updated |
++----------------+----------------------------+-------------------------------------------------+
+| Close Mailbox |
++-----------------------------------------------------------------------------------------------+
+
+Multipart Email Example
+'''''''''''''''''''''''
+
++----------------+----------------------------+-------------------------------+-----------------+
+| Open Mailbox | server=imap.googlemail.com | user=email@gmail.com | password=secret |
++----------------+----------------------------+-------------------------------+-----------------+
+| ${LATEST} = | Wait For Mail | from_email=noreply@domain.com | timeout=300 |
++----------------+----------------------------+-------------------------------+-----------------+
+| ${parts} = | Walk Multipart Email | ${LATEST} |
++----------------+----------------------------+-------------------------------+-----------------+
+| :FOR | ${i} | IN RANGE | ${parts} |
++----------------+----------------------------+-------------------------------+-----------------+
+| \\ | Walk Multipart Email | ${LATEST} |
++----------------+----------------------------+-------------------------------------------------+
+| \\ | ${content-type} = | Get Multipart Content Type |
++----------------+----------------------------+-------------------------------------------------+
+| \\ | Continue For Loop If | '${content-type}' != 'text/html' |
++----------------+----------------------------+-------------------------------+-----------------+
+| \\ | ${payload} = | Get Multipart Payload | decode=True |
++----------------+----------------------------+-------------------------------+-----------------+
+| \\ | Should Contain | ${payload} | your email |
++----------------+----------------------------+-------------------------------+-----------------+
+| \\ | ${HTML} = | Open Link From Mail | ${LATEST} |
++----------------+----------------------------+-------------------------------+-----------------+
+| \\ | Should Contain | ${HTML} | Your email |
++----------------+----------------------------+-------------------------------+-----------------+
+| Close Mailbox |
++-----------------------------------------------------------------------------------------------+
-**robotframework-imaplibrary** is a `Robot Framework
-`_ test library to test
-mail validation tasks.
+Installation
+------------
+Using ``pip``
+'''''''''''''
-Deprecation Warning
-+++++++++++++++++++
+The recommended installation method is using pip_:
-Lovely Systems does not not support this package anymore and
-do not have any follow up package in the same area. If anyone is
-interested to continue our efforts and would like to
-manage the contributors in this open source project,
-feel free to fork the package and give me a hint, so I can
-create a link to your fork!
+.. code:: bash
-best regards, Manfred (Github: schwendinger, schwendinger at lovelysystems.com)
+ pip install robotframework-imaplibrary
-Installation
-++++++++++++
+The main benefit of using ``pip`` is that it automatically installs all
+dependencies needed by the library. Other nice features are easy upgrading
+and support for un-installation:
-To install, just fetch the latest version from PyPI:.
+.. code:: bash
pip install --upgrade robotframework-imaplibrary
+ pip uninstall robotframework-imaplibrary
+
+Notice that using ``--upgrade`` above updates both the library and all
+its dependencies to the latest version. If you want, you can also install
+a specific version:
+
+.. code:: bash
+
+ pip install robotframework-imaplibrary==x.x.x
+
+Proxy configuration
+'''''''''''''''''''
+
+If you are behind a proxy, you can use ``--proxy`` command line option
+or set ``http_proxy`` and/or ``https_proxy`` environment variables to
+configure ``pip`` to use it. If you are behind an authenticating NTLM proxy,
+you may want to consider installing CNTML_ to handle communicating with it.
+
+For more information about ``--proxy`` option and using pip with proxies
+in general see:
+
+- http://pip-installer.org/en/latest/usage.html
+- http://stackoverflow.com/questions/9698557/how-to-use-pip-on-windows-behind-an-authenticating-proxy
+- http://stackoverflow.com/questions/14149422/using-pip-behind-a-proxy
+
+Manual installation
+'''''''''''''''''''
+
+If you do not have network connection or cannot make proxy to work, you need
+to resort to manual installation. This requires installing both the library
+and its dependencies yourself.
+
+- Make sure you have `Robot Framework installed`_.
+
+- Download source distributions (``*.tar.gz``) for the library:
+
+ - https://pypi.python.org/pypi/robotframework-imaplibrary
+
+- Download PGP signatures (``*.tar.gz.asc``) for signed packages.
+
+- Find each public key used to sign the package:
+
+.. code:: bash
+
+ gpg --keyserver pgp.mit.edu --search-keys D1406DE7
+
+- Select the number from the list to import the public key
+
+- Verify the package against its PGP signature:
+
+.. code:: bash
+
+ gpg --verify robotframework-imaplibrary-x.x.x.tar.gz.asc robotframework-imaplibrary-x.x.x.tar.gz
+
+- Extract each source distribution to a temporary location.
+
+- Go to each created directory from the command line and install each project using:
+
+.. code:: bash
+
+ python setup.py install
+
+If you are on Windows, and there are Windows installers available for
+certain projects, you can use them instead of source distributions.
+Just download 32bit or 64bit installer depending on your system,
+double-click it, and follow the instructions.
+
+Directory Layout
+----------------
+
+doc/
+ `Keyword documentation`_
+
+src/
+ Python source code
+
+test/
+ Test files
+
+ utest/
+ Python unit test
Usage
-+++++
+-----
-Setup in the robotframework Settings section:
+To write tests with Robot Framework and ImapLibrary,
+ImapLibrary must be imported into your Robot test suite.
-============ ================
- Setting Value
-============ ================
-Library ImapLibrary
-============ ================
++-----------------------+
+| *** Settings *** |
++---------+-------------+
+| Library | ImapLibrary |
++---------+-------------+
-\
-
-These keyword actions are available::
-
- Open Mailbox:
- Open the mailbox on a mail server with a valid authentication:
- Arguments:
- - server: the server name (e.g. imap.googlemail.com)
- - user: the user name (e.g. me@googlemail.com)
- - password: the user's password
-
- Wait for Mail:
- Wait for an incoming mail. Check the mailbox every 10 seconds
- for incoming mails until a matching email is received or the
- timeout is exceeded. Returns the mail number of the latest matching
- email.
- Arguments:
- - fromEmail: the email address of the sender (not required)
- - toEmail: the email address of the receiver (not required)
- - status: the status of the email (not required)
- - timeout: the timeout how long the mailbox shall check emails
- in seconds (defaults to 60 seconds)
-
- Get Links From Email:
- Finds all links in an email body and returns them
-
- Arguments:
- - mailNumber: is the index number of the mail to open
-
- Get Matches From Email:
- Finds all occurrences of a regular expression
-
- Arguments:
- - mailNumber: is the index number of the mail to open
- - regexp: a regular expression to find
-
- Open Link from Mail:
- Find a link in an email body and open the link. Returns the links' html.
- Arguments:
- mailNumber: the number of the email to check for a link
- linkNumber: the index of the link to open
- (defaults to 0, which is the first link)
-
- Get Email body:
- Returns an email body
- Arguments:
- mailNumber: the number of the email to check for a link
-
- Walk Multipart Email
- Returns the number of parts of a multipart email. Content is stored internally
- to be used by other multipart keywords. Subsequent calls iterate over the
- elements, and the various Get Multipart keywords retrieve their contents.
-
- Arguments:
- mailNumber: the index number of the mail to open
-
- Get Multipart Content Type
- Return the content-type for the current part of a multipart email
-
- Get Multipart Payload
- Return the payload for the current part of a multipart email
-
- Arguments:
- decode: an optional flag that indicates whether to decoding
-
- Get Multipart Field Names
- Return the list of header field names for the current multipart email
-
- Get Multipart Field
- Returns the content of a header field
-
- Arguments:
- field: a string such as 'From', 'To', 'Subject', 'Date', etc.
-
- Mark as read:
- Mark all received mails as read
-
- Close Mailbox:
- Close the mailbox after finishing all mail activities of a user.
-
-For more informaiton on `status` see: `Mailbox Status `_.
-
-Here is an example of how to use the library:
-
-============== ========================== =================================== ================================== ============= ============
- Action Argument Argument Argument Argument Argument
-============== ========================== =================================== ================================== ============= ============
-Open Mailbox server=imap.googlemail.com user=mymail@googlemail.com password=mysecretpassword
-${LATEST}= Wait for Mail fromEmail=noreply@register.com toEmail=mymailalias@googlemail.com status=UNSEEN timeout=150
-${HTML}= Open Link from Mail ${LATEST}
-Should Contain ${HTML} Your email address has been updated
-Close Mailbox
-============== ========================== =================================== ================================== ============= ============
-
-Here is an example of how to work with multipart emails, ignoring all non content-type='test/html' parts:
-
-============== ========================== =================================== =================================== ============
- Action Argument Argument Argument Argument
-============== ========================== =================================== =================================== ============
-Open Mailbox server=imap.googlemail.com user=mymail@googlemail.com password=mysecretpassword
-${LATEST}= Wait for Mail fromEmail=noreply@register.com toEmail=mymailalias@googlemail.com timeout=150
-${parts}= Walk Multipart Email ${LATEST}
-@{fields}= Get Multipart Field Names
-${from}= Get Multipart Field From
-${to}= Get Multipart Field To
-${subject}= Get Multipart Field Subject
-:FOR ${i} IN RANGE ${parts}
-\ Walk Multipart Email ${LATEST}
-\ ${content-type}= Get Multipart Content Type
-\ Continue For Loop If '${content-type}' != 'text/html'
-\ ${payload}= Get Multipart Payload decode=True
-\ Should Contain ${payload} Update your email address
-\ ${HTML}= Open Link from Mail ${LATEST}
-\ Should Contain ${HTML} Your email address has been updated
-Close Mailbox
-============== ========================== =================================== =================================== ============
+See `Robot Framework User Guide`_ for more information.
-License
-+++++++
+More information about Robot Framework standard libraries and built-in tools
+can be found in the `Robot Framework Documentation`_.
+
+Building Keyword Documentation
+------------------------------
+
+The `Keyword Documentation`_ can be found online, if you need to generate the keyword documentation, run:
+
+.. code:: bash
-The robotframework-imaplibrary is licensed under the `Apache 2.0 License
-`_.
+ make doc
+
+Run Unit Tests, and Test Coverage Report
+----------------------------------------
+
+Test the testing library, talking about dogfooding, let's run:
+
+.. code:: bash
+
+ make test
+
+Contributing
+------------
+
+If you would like to contribute code to Imap Library project you can do so through GitHub by forking the repository and sending a pull request.
+
+When submitting code, please make every effort to follow existing conventions and style in order to keep the code as readable as possible. Please also include appropriate test cases.
+
+Before your code can be accepted into the project you must also sign the `Imap Library CLA`_ (Individual Contributor License Agreement).
+
+That's it! Thank you for your contribution!
+
+License
+-------
+
+Copyright (c) 2015 Richard Huang.
+
+This library is free software, licensed under: `Apache License, Version 2.0`_.
+
+Documentation and other similar content are provided under `Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License`_.
+
+.. _Apache License, Version 2.0: https://goo.gl/qpvnnB
+.. _CNTML: http://goo.gl/ukiwSO
+.. _Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License: http://goo.gl/SNw73V
+.. _Imap Library CLA: https://goo.gl/forms/QMyqXJI2LM
+.. _Keyword Documentation: https://goo.gl/ntRuxC
+.. _Method Names and Instance Variables: https://goo.gl/NxxD0n
+.. _pip: http://goo.gl/jlJCPE
+.. _Robot Framework: http://goo.gl/lES6WM
+.. _Robot Framework Documentation: http://goo.gl/zy53tf
+.. _Robot Framework installed: https://goo.gl/PFbWqM
+.. _Robot Framework User Guide: http://goo.gl/Q7dfPB
+.. |Docs| image:: https://img.shields.io/badge/docs-latest-brightgreen.svg
+ :target: https://goo.gl/ntRuxC
+ :alt: Keyword Documentation
+.. |Version| image:: https://img.shields.io/pypi/v/robotframework-imaplibrary.svg
+ :target: https://goo.gl/q66LcA
+ :alt: Package Version
+.. |Status| image:: https://img.shields.io/pypi/status/robotframework-imaplibrary.svg
+ :target: https://goo.gl/q66LcA
+ :alt: Development Status
+.. |Python| image:: https://img.shields.io/pypi/pyversions/robotframework-imaplibrary.svg
+ :target: https://goo.gl/sXzgao
+ :alt: Python Version
+.. |Download| image:: https://img.shields.io/pypi/dm/robotframework-imaplibrary.svg
+ :target: https://goo.gl/q66LcA
+ :alt: Monthly Download
+.. |License| image:: https://img.shields.io/pypi/l/robotframework-imaplibrary.svg
+ :target: https://goo.gl/qpvnnB
+ :alt: License
diff --git a/analytics.py b/analytics.py
new file mode 100644
index 0000000..f48c23b
--- /dev/null
+++ b/analytics.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# Copyright 2015 Richard Huang
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""
+IMAP Library - a IMAP email testing library.
+"""
+
+from __future__ import print_function
+from os.path import split
+from re import sub
+import sys
+
+
+def main(argv):
+ """Adds analytics code into auto generated documentation."""
+ try:
+ path = argv[0]
+ except IndexError:
+ print("analytics.py ")
+ sys.exit(1)
+
+ with open(path) as reader:
+ content = reader.read()
+
+ analytics = """""" % (split(path)[1])
+
+ content = sub(r"
+
+
+
Opening library documentation failed
+
+ - Verify that you have JavaScript enabled in your browser.
+ - Make sure you are using a modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
+ - Check are there messages in your browser's JavaScript error log. Please report the problem if you suspect you have encountered a bug.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+", analytics + "\n", content)
+
+ with open(path, "w") as writer:
+ writer.write(content)
+
+if __name__ == "__main__":
+ main(sys.argv[1:])
diff --git a/bootstrap.py b/bootstrap.py
deleted file mode 100644
index 5f2cb08..0000000
--- a/bootstrap.py
+++ /dev/null
@@ -1,260 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2006 Zope Foundation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Bootstrap a buildout-based project
-
-Simply run this script in a directory containing a buildout.cfg.
-The script accepts buildout command-line options, so you can
-use the -c option to specify an alternate configuration file.
-"""
-
-import os, shutil, sys, tempfile, textwrap, urllib, urllib2, subprocess
-from optparse import OptionParser
-
-if sys.platform == 'win32':
- def quote(c):
- if ' ' in c:
- return '"%s"' % c # work around spawn lamosity on windows
- else:
- return c
-else:
- quote = str
-
-# See zc.buildout.easy_install._has_broken_dash_S for motivation and comments.
-stdout, stderr = subprocess.Popen(
- [sys.executable, '-Sc',
- 'try:\n'
- ' import ConfigParser\n'
- 'except ImportError:\n'
- ' print 1\n'
- 'else:\n'
- ' print 0\n'],
- stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
-has_broken_dash_S = bool(int(stdout.strip()))
-
-# In order to be more robust in the face of system Pythons, we want to
-# run without site-packages loaded. This is somewhat tricky, in
-# particular because Python 2.6's distutils imports site, so starting
-# with the -S flag is not sufficient. However, we'll start with that:
-if not has_broken_dash_S and 'site' in sys.modules:
- # We will restart with python -S.
- args = sys.argv[:]
- args[0:0] = [sys.executable, '-S']
- args = map(quote, args)
- os.execv(sys.executable, args)
-# Now we are running with -S. We'll get the clean sys.path, import site
-# because distutils will do it later, and then reset the path and clean
-# out any namespace packages from site-packages that might have been
-# loaded by .pth files.
-clean_path = sys.path[:]
-import site
-sys.path[:] = clean_path
-for k, v in sys.modules.items():
- if k in ('setuptools', 'pkg_resources') or (
- hasattr(v, '__path__') and
- len(v.__path__)==1 and
- not os.path.exists(os.path.join(v.__path__[0],'__init__.py'))):
- # This is a namespace package. Remove it.
- sys.modules.pop(k)
-
-is_jython = sys.platform.startswith('java')
-
-setuptools_source = 'http://peak.telecommunity.com/dist/ez_setup.py'
-distribute_source = 'http://python-distribute.org/distribute_setup.py'
-
-# parsing arguments
-def normalize_to_url(option, opt_str, value, parser):
- if value:
- if '://' not in value: # It doesn't smell like a URL.
- value = 'file://%s' % (
- urllib.pathname2url(
- os.path.abspath(os.path.expanduser(value))),)
- if opt_str == '--download-base' and not value.endswith('/'):
- # Download base needs a trailing slash to make the world happy.
- value += '/'
- else:
- value = None
- name = opt_str[2:].replace('-', '_')
- setattr(parser.values, name, value)
-
-usage = '''\
-[DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options]
-
-Bootstraps a buildout-based project.
-
-Simply run this script in a directory containing a buildout.cfg, using the
-Python that you want bin/buildout to use.
-
-Note that by using --setup-source and --download-base to point to
-local resources, you can keep this script from going over the network.
-'''
-
-parser = OptionParser(usage=usage)
-parser.add_option("-v", "--version", dest="version",
- help="use a specific zc.buildout version")
-parser.add_option("-d", "--distribute",
- action="store_true", dest="use_distribute", default=False,
- help="Use Distribute rather than Setuptools.")
-parser.add_option("--setup-source", action="callback", dest="setup_source",
- callback=normalize_to_url, nargs=1, type="string",
- help=("Specify a URL or file location for the setup file. "
- "If you use Setuptools, this will default to " +
- setuptools_source + "; if you use Distribute, this "
- "will default to " + distribute_source +"."))
-parser.add_option("--download-base", action="callback", dest="download_base",
- callback=normalize_to_url, nargs=1, type="string",
- help=("Specify a URL or directory for downloading "
- "zc.buildout and either Setuptools or Distribute. "
- "Defaults to PyPI."))
-parser.add_option("--eggs",
- help=("Specify a directory for storing eggs. Defaults to "
- "a temporary directory that is deleted when the "
- "bootstrap script completes."))
-parser.add_option("-t", "--accept-buildout-test-releases",
- dest='accept_buildout_test_releases',
- action="store_true", default=False,
- help=("Normally, if you do not specify a --version, the "
- "bootstrap script and buildout gets the newest "
- "*final* versions of zc.buildout and its recipes and "
- "extensions for you. If you use this flag, "
- "bootstrap and buildout will get the newest releases "
- "even if they are alphas or betas."))
-parser.add_option("-c", None, action="store", dest="config_file",
- help=("Specify the path to the buildout configuration "
- "file to be used."))
-
-options, args = parser.parse_args()
-
-# if -c was provided, we push it back into args for buildout's main function
-if options.config_file is not None:
- args += ['-c', options.config_file]
-
-if options.eggs:
- eggs_dir = os.path.abspath(os.path.expanduser(options.eggs))
-else:
- eggs_dir = tempfile.mkdtemp()
-
-if options.setup_source is None:
- if options.use_distribute:
- options.setup_source = distribute_source
- else:
- options.setup_source = setuptools_source
-
-if options.accept_buildout_test_releases:
- args.append('buildout:accept-buildout-test-releases=true')
-args.append('bootstrap')
-
-try:
- import pkg_resources
- import setuptools # A flag. Sometimes pkg_resources is installed alone.
- if not hasattr(pkg_resources, '_distribute'):
- raise ImportError
-except ImportError:
- ez_code = urllib2.urlopen(
- options.setup_source).read().replace('\r\n', '\n')
- ez = {}
- exec ez_code in ez
- setup_args = dict(to_dir=eggs_dir, download_delay=0)
- if options.download_base:
- setup_args['download_base'] = options.download_base
- if options.use_distribute:
- setup_args['no_fake'] = True
- ez['use_setuptools'](**setup_args)
- if 'pkg_resources' in sys.modules:
- reload(sys.modules['pkg_resources'])
- import pkg_resources
- # This does not (always?) update the default working set. We will
- # do it.
- for path in sys.path:
- if path not in pkg_resources.working_set.entries:
- pkg_resources.working_set.add_entry(path)
-
-cmd = [quote(sys.executable),
- '-c',
- quote('from setuptools.command.easy_install import main; main()'),
- '-mqNxd',
- quote(eggs_dir)]
-
-if not has_broken_dash_S:
- cmd.insert(1, '-S')
-
-find_links = options.download_base
-if not find_links:
- find_links = os.environ.get('bootstrap-testing-find-links')
-if find_links:
- cmd.extend(['-f', quote(find_links)])
-
-if options.use_distribute:
- setup_requirement = 'distribute'
-else:
- setup_requirement = 'setuptools'
-ws = pkg_resources.working_set
-setup_requirement_path = ws.find(
- pkg_resources.Requirement.parse(setup_requirement)).location
-env = dict(
- os.environ,
- PYTHONPATH=setup_requirement_path)
-
-requirement = 'zc.buildout'
-version = options.version
-if version is None and not options.accept_buildout_test_releases:
- # Figure out the most recent final version of zc.buildout.
- import setuptools.package_index
- _final_parts = '*final-', '*final'
- def _final_version(parsed_version):
- for part in parsed_version:
- if (part[:1] == '*') and (part not in _final_parts):
- return False
- return True
- index = setuptools.package_index.PackageIndex(
- search_path=[setup_requirement_path])
- if find_links:
- index.add_find_links((find_links,))
- req = pkg_resources.Requirement.parse(requirement)
- if index.obtain(req) is not None:
- best = []
- bestv = None
- for dist in index[req.project_name]:
- distv = dist.parsed_version
- if _final_version(distv):
- if bestv is None or distv > bestv:
- best = [dist]
- bestv = distv
- elif distv == bestv:
- best.append(dist)
- if best:
- best.sort()
- version = best[-1].version
-if version:
- requirement = '=='.join((requirement, version))
-cmd.append(requirement)
-
-if is_jython:
- import subprocess
- exitcode = subprocess.Popen(cmd, env=env).wait()
-else: # Windows prefers this, apparently; otherwise we would prefer subprocess
- exitcode = os.spawnle(*([os.P_WAIT, sys.executable] + cmd + [env]))
-if exitcode != 0:
- sys.stdout.flush()
- sys.stderr.flush()
- print ("An error occurred when trying to install zc.buildout. "
- "Look above this message for any errors that "
- "were output by easy_install.")
- sys.exit(exitcode)
-
-ws.add_entry(eggs_dir)
-ws.require(requirement)
-import zc.buildout.buildout
-zc.buildout.buildout.main(args)
-if not options.eggs: # clean up temporary egg directory
- shutil.rmtree(eggs_dir)
diff --git a/buildout.cfg b/buildout.cfg
deleted file mode 100644
index ae8084e..0000000
--- a/buildout.cfg
+++ /dev/null
@@ -1,12 +0,0 @@
-[buildout]
-develop = .
-parts = test
-versions = versions
-
-[versions]
-zope.testing = 4.0.0
-
-[test]
-recipe = corejet.testrunner
-defaults = ['--auto-color', '--tests-pattern', '^f?tests$']
-eggs = robotframework-imaplibrary [test]
diff --git a/doc/ImapLibrary.html b/doc/ImapLibrary.html
new file mode 100644
index 0000000..eff6bb4
--- /dev/null
+++ b/doc/ImapLibrary.html
@@ -0,0 +1,840 @@
+
+
+