소스 검색

merge python integration branch into master

Noah Vogt 3 년 전
부모
커밋
3fa1521d24

+ 1 - 0
.gitignore

@@ -16,3 +16,4 @@
 .cxx
 local.properties
 app/release/
+*__pycache__*

+ 17 - 1
app/build.gradle

@@ -1,5 +1,6 @@
 plugins {
     id 'com.android.application'
+    id 'com.chaquo.python'
 }
 
 android {
@@ -16,9 +17,23 @@ android {
         versionCode 1
         versionName "1.0"
 
-        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+        ndk {
+            abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
+        }
+        python {
+            pip {
+                //install "email"
+                //install "imaplib"
+            }
+            buildPython "/usr/bin/python3.8"
+        }
+    packagingOptions {
+        exclude 'META-INF/NOTICE.md'
     }
 
+
+        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+
     buildTypes {
         release {
             minifyEnabled false
@@ -30,6 +45,7 @@ android {
         targetCompatibility JavaVersion.VERSION_1_8
     }
 }
+}
 
 dependencies {
 

+ 2 - 1
app/src/main/AndroidManifest.xml

@@ -1,6 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.noahvogt.miniprojekt">
+    <uses-permission android:name="android.permission.INTERNET" />
 
     <application
         android:allowBackup="true"
@@ -22,4 +23,4 @@
         <activity android:name=".ui.home.SettingsActivity"/>
     </application>
 
-</manifest>
+</manifest>

+ 69 - 37
app/src/main/java/com/noahvogt/miniprojekt/MainActivity.java

@@ -2,7 +2,6 @@ package com.noahvogt.miniprojekt;
 
 import android.content.Intent;
 import android.os.Bundle;
-
 import android.view.Menu;
 import android.view.View;
 import android.widget.Button;
@@ -35,15 +34,27 @@ import java.util.ArrayList;
 
 import com.google.android.material.navigation.NavigationView;
 
-
 import androidx.navigation.NavController;
 import androidx.navigation.Navigation;
 import androidx.navigation.ui.AppBarConfiguration;
 import androidx.navigation.ui.NavigationUI;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
 
-
+import com.chaquo.python.PyObject;
+import com.chaquo.python.Python;
+import com.chaquo.python.android.AndroidPlatform;
 import com.google.android.material.navigation.NavigationView;
 import com.google.android.material.snackbar.Snackbar;
+import com.noahvogt.miniprojekt.ui.home.CustomAdapter;
+import com.noahvogt.miniprojekt.ui.home.Data;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.chaquo.python.android.PyApplication;
+
+import com.noahvogt.miniprojekt.mailFunctions;
 
 import static com.noahvogt.miniprojekt.R.id.drawer_layout;
 
@@ -51,27 +62,28 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
 
     private AppBarConfiguration mAppBarConfiguration;
 
-    //imported by simon 2.may from RecyclerView Programm, changed to 23.may Simon to ArrayList<Data>...
+    /* declare vars that should always be used / shown by default */
     protected ArrayList<Data> data;
-
     private AlertDialog dialog;
+    private EditText newemail_name, newemail_email, newemail_password; /* may not be private */
 
     private EditText newemail_name, newemail_email, newemail_password; // may not be private
 
-    // empty descriptor
+    /* empty descriptor */
     public MainActivity() {
-    }
-
+        }
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_main);
 
-
-
-
-        // define button listeners
+        /*
+        if (! Python.isStarted()) {
+           Python.start(new AndroidPlatform(this));
+        }
+         define button listeners
+        */
 
         Button add_email_button = (Button) findViewById(R.id.addEmailButton);
         add_email_button.setOnClickListener(new View.OnClickListener() {
@@ -90,13 +102,17 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
             }
         });
 
+        /* invoke toolbar */
         Toolbar toolbar = findViewById(R.id.toolbar);
         setSupportActionBar(toolbar);
 
+        /* invoke drawer */
         DrawerLayout drawer = findViewById(drawer_layout);
         NavigationView navigationView = findViewById(R.id.nav_view);
-        // Passing each menu ID as a set of Ids because each
-        // menu should be considered as top level destinations.
+        /*
+         Passing each menu ID as a set of Ids because each
+         menu should be considered as top level destinations.
+        */
         mAppBarConfiguration = new AppBarConfiguration.Builder(
                 R.id.nav_home, R.id.nav_gallery, R.id.nav_slideshow)
                 .setDrawerLayout(drawer)
@@ -105,14 +121,16 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
         NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration);
         NavigationUI.setupWithNavController(navigationView, navController);
 
+        /* invoke recycleViewer */
+
         //initDataset();
-        // Lookup the recyclerview in activity layou
+        /* Lookup the recyclerview in activity layout */
         RecyclerView recyclerView = findViewById(R.id.recyclerView);
-        // Initialize contacts
+        /* Initialize contacts */
         data = Data.createContactsList(20);
-        // Create adapter passing in the sample user data
+        /* Create adapter passing in the sample user data */
         CustomAdapter adapter = new CustomAdapter(data);
-        // Attach the adapter to the recyclerview to populate items
+        /* Attach the adapter to the recyclerview to populate items */
         recyclerView.setAdapter(adapter);
         recyclerView.setLayoutManager(new LinearLayoutManager(this));
 
@@ -131,7 +149,7 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
 
     @Override
     public boolean onCreateOptionsMenu(Menu menu) {
-        // Inflate the menu; this adds items to the action bar if it is present.
+        /* Inflate the menu; this adds items to the action bar if it is present. */
         getMenuInflater().inflate(R.menu.create_message_options_menu, menu);
         return true;
     }
@@ -144,35 +162,40 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
     }
 
 
-    // better leave empty to avoid any listener disambiguity
+    /* better leave empty to avoid any listener disambiguity */
     public void onClick(View view) {}
 
 
     public void createNewEmailDialog(){
-        // define View window
+        /* define View window */
         AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this);
         final View emailPopupView = getLayoutInflater().inflate(R.layout.popup, null);
 
-        // init text field variables
+        /* init text field variables */
         newemail_name = emailPopupView.findViewById(R.id.popup_material_name_asking_text);
         newemail_email = emailPopupView.findViewById(R.id.popup_material_email_asking_text);
         newemail_password = emailPopupView.findViewById(R.id.popup_material_password_asking_text);
 
-        // init button variables
+        /* init button variables */
         Button newemail_save_button = (Button) emailPopupView.findViewById(R.id.saveButton);
-        // may not be private
+        /* may not be private */
         Button newemail_cancel_button = (Button) emailPopupView.findViewById(R.id.cancelButton);
 
-        // open View window
-        dialogBuilder.setView(emailPopupView);
+
+        /* open View window */
+            dialogBuilder.setView(emailPopupView);
         dialog = dialogBuilder.create();
         dialog.show();
 
-        // store user input
+        if (! Python.isStarted()) {
+            Python.start(new AndroidPlatform(this));
+        }
+
+        /* store user input */
         newemail_save_button.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
-                // store user input (only needed for DEBUGGING)
+                /* store user input (only needed for DEBUGGING) */
                 String name = newemail_name.getText().toString();
                 String email = newemail_email.getText().toString();
                 String password = newemail_password.getText().toString();
@@ -181,36 +204,45 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
                     return;
                 }
 
-                // show all strings the user gave, this will later be stored to a secure database and checked for validation
-                showToast(name);
-                showToast(email);
-                showToast(password);
+                /* connect to mail server and print various debugging output */
+                if (mailFunctions.canConnect(name, email, password) == Boolean.TRUE) {
+                    showToast("was able to connect");
+                    List l =  mailFunctions.listMailboxes(mailFunctions.getIMAPConnection(name, email, password));
+                    for (int i = 0; i < l.size(); i++) {
+                        showToast(l.get(i).toString());
+                    }
+                } else {
+                    showToast("failed to connect");
+
+                    /* show all strings the user gave, this will later be stored to a secure database and checked for validation */
+                    showToast(name);
+                    showToast(email);
+                    showToast(password);
+                }
 
 
-                showSnackbar(emailPopupView,"save button clicked");
             }
         });
 
         newemail_cancel_button.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
-                // define save button here
                 dialog.dismiss();
             }
         });
 
     }
 
-    // show debug output in  specific view
+    /* show debug output in  specific view */
     private void showSnackbar(View View, String text) {
         Snackbar.make(View, text, Snackbar.LENGTH_LONG)
                 .setAction("Action", null).show();
     }
 
-    // like showSnackbar(), but global and uglier
+    /* like showSnackbar(), but global and uglier */
     private void showToast(String text) {
         Toast.makeText(MainActivity.this, text, Toast.LENGTH_SHORT).show();
     }
 
 
-}
+}

+ 31 - 3
app/src/main/java/com/noahvogt/miniprojekt/mailFunctions.java

@@ -3,9 +3,37 @@ package com.noahvogt.miniprojekt;
 import android.util.Patterns;
 import android.widget.EditText;
 
+import com.chaquo.python.PyObject;
+import com.chaquo.python.Python;
+
+import java.util.HashMap;
+import java.util.List;
+
 public class mailFunctions {
 
-    // TODO: resolve endIcon style conflict
+    public static boolean canConnect(String host, String email, String password) {
+        Python python = Python.getInstance();
+        PyObject pythonMailFunctions = python.getModule("mailFunctions");
+        return pythonMailFunctions.callAttr("checkConnection", host, email, password, 993).toBoolean();
+    }
+
+    public static PyObject getIMAPConnection(String host, String email, String password) {
+        Python python = Python.getInstance();
+        PyObject pythonMailFunctions = python.getModule("mailFunctions");
+        return pythonMailFunctions.callAttr("connect", host, email, password, 993);
+    }
+
+    public static List listMailboxes(PyObject IMAPConnection) {
+        Python python = Python.getInstance();
+        PyObject pythonMailFunctions = python.getModule("mailFunctions");
+        return pythonMailFunctions.callAttr("listMailboxes", IMAPConnection).asList();
+    }
+
+    public static List fetchMailsFromBox(PyObject IMAPConnection, String Folder) {
+        Python python = Python.getInstance();
+        PyObject pythonMailFunctions = python.getModule("mailFunctions");
+        return pythonMailFunctions.callAttr("fetchMails", IMAPConnection, Folder).asList();
+    }
 
     public static boolean validateName(EditText emailName) {
         String name = emailName.getText().toString().trim();
@@ -51,13 +79,13 @@ public class mailFunctions {
 
     public static boolean validateSubject(EditText emailSubject) {
         String subject = emailSubject.getText().toString();
-        // TODO: check email protocol specification for what is allowed for subjects
+        /* TODO: check email protocol specification for what is allowed for subjects */
         return true;
     }
 
     public static boolean validateMessageBody(EditText emailMessageBody) {
         String messageBody = emailMessageBody.getText().toString();
-        // TODO: check email protocol specification for what is allowed for message bodies
+        /* TODO: check email protocol specification for what is allowed for message bodies */
         return true;
     }
 

+ 16 - 16
app/src/main/java/com/noahvogt/miniprojekt/messageCreateFragment.java

@@ -25,7 +25,7 @@ public class messageCreateFragment extends DialogFragment implements PopupMenu.O
 
 
 
-    // set theming style
+    /* set theming style */
     @Override
     public void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -36,10 +36,10 @@ public class messageCreateFragment extends DialogFragment implements PopupMenu.O
     @Nullable
     @Override
     public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
-        // set and inflate layout
+        /* set and inflate layout */
         View view = inflater.inflate(R.layout.message_create_fragment, container, false);
 
-        // init vars
+        /* init vars */
 
         ImageButton closeButton = view.findViewById(R.id.create_message_close_button);
         ImageButton sendButton = view.findViewById(R.id.create_message_send_button);
@@ -51,15 +51,15 @@ public class messageCreateFragment extends DialogFragment implements PopupMenu.O
         EditText subjectObject = (EditText) view.findViewById(R.id.create_message_subject_text);
         EditText messageBodyObject = (EditText) view.findViewById(R.id.create_message_body_text);
 
-        // get string vars, MAYBE NOT HERE
+        /* get string vars, MAYBE NOT HERE */
         String sendingAddress = sendingAddressObject.getText().toString();
         String receivingAddress = receivingAddressObject.getText().toString();
         String subject = subjectObject.getText().toString();
         String messageBody = messageBodyObject.getText().toString();
 
-        // TODO: add cc + bcc functionality
+        /* TODO: add cc + bcc functionality */
 
-        // button listeners
+        /* button listeners */
 
         closeButton.setOnClickListener(new View.OnClickListener() {
             @Override
@@ -67,13 +67,13 @@ public class messageCreateFragment extends DialogFragment implements PopupMenu.O
                 String subject = subjectObject.getText().toString();
                 String messageBody = messageBodyObject.getText().toString();
 
-                // give alert dialog box to user in case input fields are not empty
+                /* give alert dialog box to user in case input fields are not empty */
 
                 if (subject.isEmpty() && messageBody.isEmpty()) {
                     dismiss();
                 }
                 else {
-                    // setup dialog
+                    /* setup dialog */
                     AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(getActivity());
                     alertDialogBuilder.setTitle("Warning");
                     alertDialogBuilder
@@ -81,18 +81,18 @@ public class messageCreateFragment extends DialogFragment implements PopupMenu.O
                             .setCancelable(false)
                             .setPositiveButton("Yes",new DialogInterface.OnClickListener() {
                                 public void onClick(DialogInterface dialog, int id) {
-                                    // if this button is clicked, close the whole fragment
+                                    /* if this button is clicked, close the whole fragment */
                                     dismiss();
                                 }
                             })
                             .setNegativeButton("No",new DialogInterface.OnClickListener() {
                                 public void onClick(DialogInterface dialog,int id) {
-                                    // if this button is clicked, just close the dialog box
+                                    /* if this button is clicked, just close the dialog box */
                                     dialog.cancel();
                                 }
                             });
 
-                    // create + show alert dialog
+                    /* create + show alert dialog */
                     AlertDialog alertDialog = alertDialogBuilder.create();
                     alertDialog.show();
                 }
@@ -102,7 +102,7 @@ public class messageCreateFragment extends DialogFragment implements PopupMenu.O
         attachButton.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
-                // TODO: add file attachment functionality
+                /* TODO: add file attachment functionality */
             }
         });
 
@@ -119,13 +119,13 @@ public class messageCreateFragment extends DialogFragment implements PopupMenu.O
         sendButton.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
-                // init vars, MAYBE NEEDED FOR LATER
+                /* init vars, MAYBE NEEDED FOR LATER */
                 String sendingAddress = sendingAddressObject.getText().toString();
                 String receivingAddress = receivingAddressObject.getText().toString();
                 String subject = subjectObject.getText().toString();
                 String messageBody = messageBodyObject.getText().toString();
 
-                // check for valid input
+                /* check for valid input */
                 if (mailFunctions.validateMessageBody(messageBodyObject) && mailFunctions.validateSubject(subjectObject) &&
                 mailFunctions.validateEmail(receivingAddressObject) && mailFunctions.validateEmail(sendingAddressObject) &&
                 !mailFunctions.checkForSameEmail(sendingAddressObject, receivingAddressObject)) {
@@ -135,7 +135,7 @@ public class messageCreateFragment extends DialogFragment implements PopupMenu.O
                     Toast.makeText(getActivity(), "Please check your input", Toast.LENGTH_SHORT).show();
                 }
 
-                // TODO: implement actual sending functionality
+                /* TODO: implement actual sending functionality */
             }
         });
 
@@ -168,7 +168,7 @@ public class messageCreateFragment extends DialogFragment implements PopupMenu.O
             case R.id.create_message_item_4:
                 Toast.makeText(getActivity(), "item 4 clicked", Toast.LENGTH_LONG).show();
                 return true;
-            default: // this case should never occur
+            default: /* this case should never occur */
                 return false;
         }
     }

+ 2 - 0
app/src/main/python/helloworldscript.py

@@ -0,0 +1,2 @@
+def hi():
+    return "python says hi"

+ 118 - 0
app/src/main/python/mailFunctions.py

@@ -0,0 +1,118 @@
+import imaplib, email, os
+
+def errorMsgExit(error_msg):
+    print("Error: " + error_msg)
+
+def checkConnection(host, username, password, port):
+    try:
+        connection = imaplib.IMAP4_SSL(host, port)
+        connection.login(username, password)
+        connection.logout()
+        return True
+    except Exception as e:
+        print(str(e))
+        return False
+
+def connect(host, username, password, port):
+    connect = imaplib.IMAP4_SSL(host, port)
+    connect.login(username, password)
+    connect.enable("UTF8=ACCEPT")
+    return connect
+
+def listMailboxes(connection):
+    mailboxes = connection.list()
+    formatted_mailbox_list = []
+
+    for items in mailboxes:
+        if type(items) == list:
+            for raw_box_string in items:
+                box_string = str(raw_box_string)
+                # TODO: handle cases when folder contains subfolders
+                modified_box_string = (box_string[box_string.find('"/" ')+4:-1])
+
+                # strip unneeded "'s surrounding the folder name
+                if modified_box_string.startswith('"') and modified_box_string.endswith('"'):
+                    modified_box_string = modified_box_string[1:-1]
+
+                formatted_mailbox_list.append(modified_box_string)
+
+    connection.logout()
+    return formatted_mailbox_list
+
+def fetchMails(connection, inbox):
+    status, messages = connection.select(inbox)
+    print("status-------\n" + status)
+    print("messages-------\n" + str(messages))
+    # number of top emails to fetch
+    N = 3
+    # total number of emails
+    messages_int = int(messages[0])
+    print("message_int------\n" + str(messages_int))
+
+    typ, data = connection.search(None, 'ALL')
+    output_list = []
+    for num in data[0].split():
+        output_dict = {}
+        typ, data = connection.fetch(num, '(RFC822)')
+        msg = email.message_from_bytes(data[0][1])
+
+        #print(msg)
+
+        raw_string = email.header.decode_header(msg['Subject'])[0]
+        raw_from = email.header.decode_header(msg['From'])[0]
+        raw_to = email.header.decode_header(msg['To'])[0]
+        raw_date = email.header.decode_header(msg['Date'])[0]
+
+        raw_msg = str(msg)
+
+        primitive_body = raw_msg[raw_msg.find('\n\n'):].strip()
+
+        #raw_body = email.header.decode_header(msg['Body'])[0][0]
+
+        # set subject to an empty string when not found
+        try:
+            if raw_string[1] == 'utf-8':
+                subject = raw_string[0].raw_string('utf-8')
+            else:
+                subject = raw_string[0]
+        except AttributeError:
+            subject=""
+
+        #print("subject: {}".format(subject))
+
+        output_dict['subject'] = subject
+        output_dict['from'] = raw_from[0]
+        output_dict['to'] = raw_to[0]
+        output_dict['date'] = raw_date[0]
+        output_dict['content'] = primitive_body
+
+        output_list.append(output_dict)
+
+    connection.close()
+    connection.logout()
+
+    return output_list
+
+def afetchMails(con):
+    con.select("Sent")
+    status, email_ids = con.search(None, "ALL")
+    if status != 'OK':
+        raise Exception("Error running imap search for spinvox messages: "
+                        "%s" % status)
+
+    print(email_ids[0])
+    fetch_ids = ','.join(str(email_ids[0]).split())
+    status, data = con.fetch(3, '(RFC822)')
+    if status != 'OK':
+        raise Exception("Error running imap fetch for spinvox message: "
+                        "%s" % status)
+    for i in range(3,4):
+        header_msg = email.message_from_string(data[i * 3 + 0][1])
+        subject = header_msg['Subject'],
+        print(subject)
+        date = header_msg['Date'],
+        print(date)
+        body = data[i * 3 + 1][1]
+        print(body)
+    connection.close()
+    connection.logout()

+ 4 - 5
build.gradle

@@ -3,12 +3,11 @@ buildscript {
     repositories {
         google()
         jcenter()
+        maven { url "https://chaquo.com/maven" }
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:4.2.1'
-
-        // NOTE: Do not place your application dependencies here; they belong
-        // in the individual module build.gradle files
+        classpath 'com.android.tools.build:gradle:4.2.0'
+        classpath "com.chaquo.python:gradle:9.1.0"
     }
 }
 
@@ -21,4 +20,4 @@ allprojects {
 
 task clean(type: Delete) {
     delete rootProject.buildDir
-}
+}

+ 3 - 3
gradle/wrapper/gradle-wrapper.properties

@@ -1,6 +1,6 @@
-#Mon Apr 19 17:45:09 CEST 2021
+#Tue Aug 31 15:54:45 CEST 2021
 distributionBase=GRADLE_USER_HOME
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
 distributionPath=wrapper/dists
-zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
+zipStoreBase=GRADLE_USER_HOME

+ 110 - 0
tests/mailFunctions.py

@@ -0,0 +1,110 @@
+import imaplib, email, os
+
+def errorMsgExit(error_msg):
+    print("Error: " + error_msg)
+
+def checkConnection(host, username, password, port):
+    try:
+        connection = imaplib.IMAP4_SSL(host, port)
+        connection.login(username, password)
+        connection.logout()
+        return True
+    except Exception as e:
+        print(str(e))
+        return False
+
+def connect(host, username, password, port):
+    connect = imaplib.IMAP4_SSL(host, port)
+    connect.login(username, password)
+    connect.enable("UTF8=ACCEPT")
+    return connect
+
+def listMailboxes(connection):
+    mailboxes = connection.list()
+    formatted_mailbox_list = []
+
+    for items in mailboxes:
+        if type(items) == list:
+            for raw_box_string in items:
+                box_string = str(raw_box_string)
+                # TODO: handle cases when folder contains subfolders
+                modified_box_string = (box_string[box_string.find('"/" ')+4:-1])
+
+                # strip unneeded "'s surrounding the folder name
+                if modified_box_string.startswith('"') and modified_box_string.endswith('"'):
+                    modified_box_string = modified_box_string[1:-1]
+
+                formatted_mailbox_list.append(modified_box_string)
+
+    connection.logout()
+    return formatted_mailbox_list
+
+def fetchMails(connection, inbox):
+    status, messages = connection.select(inbox)
+    print("status-------\n" + status)
+    print("messages-------\n" + str(messages))
+    # number of top emails to fetch
+    N = 3
+    # total number of emails
+    messages_int = int(messages[0])
+    print("message_int------\n" + str(messages_int))
+
+    typ, data = connection.search(None, 'ALL')
+    output_list = []
+    for num in data[0].split():
+        typ, data = connection.fetch(num, '(RFC822)')
+        msg = email.message_from_bytes(data[0][1])
+        #print(type(msg))
+        #print(msg)
+        raw_subject = email.header.decode_header(msg['Subject'])[0]
+        #raw_body = email.header.decode_header(msg['Body'])[0][0]
+        '''
+        if decode[1] == 'utf-8':
+            subject = decode[0].decode('utf-8')
+        else:
+            subject = decode[0]
+        '''
+        #print("subject: {}".format(subject))
+        #input()
+        #print('Message %s\n%s\n' % (num, data[0][1]))
+        #print('Message %s\n%s\n' % (num, data[0][1].split()))
+        #print('%s\n' % (len(data[0][1].split())))
+        '''
+        j = 0
+        for i in range(len(str(msg))):
+            if str(msg)[i] == "\n":
+                print(str(msg)[j:i])
+                j = int(i)
+        '''
+
+
+        output_list.append(str(raw_subject))
+
+    connection.close()
+    connection.logout()
+
+    return output_list
+
+def afetchMails(con):
+    con.select("Sent")
+    status, email_ids = con.search(None, "ALL")
+    if status != 'OK':
+        raise Exception("Error running imap search for spinvox messages: "
+                        "%s" % status)
+
+    print(email_ids[0])
+    fetch_ids = ','.join(str(email_ids[0]).split())
+    status, data = con.fetch(3, '(RFC822)')
+    if status != 'OK':
+        raise Exception("Error running imap fetch for spinvox message: "
+                        "%s" % status)
+    for i in range(3,4):
+        header_msg = email.message_from_string(data[i * 3 + 0][1])
+        subject = header_msg['Subject'],
+        print(subject)
+        date = header_msg['Date'],
+        print(date)
+        body = data[i * 3 + 1][1]
+        print(body)
+    connection.close()
+    connection.logout()