Android Tutorial Using POP3 to communicate with Android devices

Many developers face the challenge of sending data to remote devices. These devices can be at times offline, sleeping or without proper network coverage.
There are several possible solutions. The device can contact a web server which will return the required data.
Another solution is to use Google push notification framework.
Here I want to present a third solution which doesn't require any custom server and is pretty simple.
Using the Net library a device can connect to a mail server and download the mail messages.
This solution can fit very well in many cases and is very simple to manage. Mail servers are very common and are easy to work with.
All you need is an email service that supports POP3. Gmail is one such service.

The POP3 object from the Net library returns the raw messages as strings.
Additional work is required to get the message fields and especially to extract attachments from the messages.
MailParser code module is included in the attached project.
MailParser parses the messages, saves the attachments and returns Messages objects which hold the various fields.

MailParser cannot be used as a real mail client. There are many possible formats and encodings. MailParser can handle simple formats with zero or more attachments.

Parsing a message is done by calling:
B4X:
      Dim m As Message
      m = MailParser.ParseMail(MessageText, File.DirRootExternal)
The first parameter is the raw message and the second is the folder that the attachments will be saved to.

MailParser requires StringUtils library for the base64 decoding.
 

Attachments

  • MailParser.zip
    6.5 KB · Views: 2,786

thedesolatesoul

Expert
Licensed User
Longtime User
Very interesting!!!
But I am not completely sure how this will work.
You set an email address app@gmail.com and save the username/password in the app to be able to retrieve the message.
How does the sending server know how to send it to a particular device? It may be useful for broadcast but cant you put in an ID for each device?
Also, doesnt POP retrieval delete the message from the server, in that case how do you broadcast to all devices?
Thanks for this though :)
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
There is nothing special here. It is not a push service. The device should connect to the server and check for mails. The last parameter in POP3.DownloadMessage determines whether the mail will be deleted after it is downloaded or not.

If you are using a single mail account for multiple devices then you can use the message subject or something similar to distinguish between different targeted devices.
 

alain bertrand

Member
Licensed User
Longtime User
Erel,
Mailparser module is working fine returning the string (eg):
Parser SubjectField =?utf-8?Q?Mademoiselle_Julie_au_Th=C3=A9=C3=A2tre_du_Parc?=
How to get rid of "=?utf-8?Q?" and "?=" to return just:
Mademoiselle Julie au Théâtre du Parc
I guess I'm not the first to ask, but I've found the answer.
Thanks.
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
You can use this code:
B4X:
Sub Activity_Create(FirstTime As Boolean)
   Log(DecodeQuotePrintable("=?utf-8?Q?Mademoiselle_Julie_au_Th=C3=A9=C3=A2tre_du_Parc?="))
End Sub

Sub DecodeQuotePrintable(q As String) As String
   Dim m As Matcher
   m = Regex.Matcher("=\?([^?]*)\?Q\?(.*)\?=$", q)
   If m.Find Then
      Dim charset As String
      Dim data As String
      charset = m.Group(1)
      data = m.Group(2)
      Dim bytes As List
      bytes.Initialize
      Dim i As Int
      Do While i < data.Length
         Dim c As String
         c = data.CharAt(i)
         If c = "_" Then
            bytes.AddAll(" ".GetBytes(charset))
         Else If c = "=" Then
            Dim hex As String
            hex = data.CharAt(i + 1) & data.CharAt(i + 2)
            i = i + 2
            bytes.Add(Bit.ParseInt(hex, 16))
         Else
            bytes.AddAll(c.GetBytes(charset))
         End If
         i = i + 1
      Loop
      Dim b(bytes.Size) As Byte
      For i = 0 To bytes.Size - 1
         b(i) = bytes.Get(i)
      Next
      Return BytesToString(b, 0, b.Length, charset)
   Else
      Return q
   End If
End Sub
Note that it wasn't tested thoroughly enough...
 

alain bertrand

Member
Licensed User
Longtime User
Great ! I didn't expect a so quick answer.
So it isn't a built-in function.
We have got to code. Thanks * 1000 for doing it.
What would we make without regular expressions ?
 

Mickster

Active Member
Licensed User
Longtime User
Could someone please demonstrate how I can use this code to obtain the subject of an email?
 

William Hunter

Active Member
Licensed User
Longtime User
Net Library and mailparser

Could someone please demonstrate how I can use this code to obtain the subject of an email?
I too have been trying to find a way to use native B4A tools to obtain header info. Without the means of using messageID as a pointer, I can't find a way. I would be most appreciative of any help in this regard. :sign0085:

Best regards
 

Mickster

Active Member
Licensed User
Longtime User
It would be useful to be able to read the email subject before downloading the entire thing including attachments, since there will be many emails in the account and many large attachments.

At the moment I'm downloading all the emails and I'm noticing that each email seems to be held in the device's memory. It piles up QUICK. Any reason for this?
 

wl

Well-Known Member
Licensed User
Longtime User
I have created a extended POP3 library that should be able to this. William Hunter has been using it: I just created it and have not used it really myself (yet)
 

sacad

Member
Licensed User
Longtime User
Struggeling to see inbox messages?

Hi ive downloaded the mailparser app and also have the required libaries but cannot get the application to display any email messages?
Im at gmail and this is what ive done in the activity_create event
If FirstTime Then
pop.Initialize("pop.gmail.com",995,"my gmail adress with .com","my password of gmail","pop")
End If
pop.ListMessages
end sub

dont know if the server and port is incorrect coz found that on net
 

sacad

Member
Licensed User
Longtime User
Why my email inbox messages does not display?

This is my whole program when i run the emulator it is blank showing no messages. what must i do. i did send email to that account and have internet but the emulator shows nothing. im using the core(v 1.9) net(version 1.20) and stringutils(version 1.0)


Sub Process_Globals
Dim pop As POP3
End Sub
Sub Globals

End Sub
Sub Activity_Create(FirstTime As Boolean)
If FirstTime Then
pop.useSSL = True
pop.Initialize("pop.gmail.com",995,"my email.gmail.com","my password",pop)
pop.useSSL = True

End If
pop.useSSL = True
pop.ListMessages

End Sub

Sub POP_ListCompleted (Success As Boolean, Messages As Map)
If Success = False Then
Log(LastException.Message)
Else
'download all messages
'change last parameter to True if you want to delete the messages from the server
For i = 0 To Messages.Size - 1
pop.DownloadMessage(Messages.GetKeyAt(i), False)
Next
End If
pop.Close
End Sub
Sub POP_DownloadCompleted (Success As Boolean, MessageId As Int, MessageText As String)
If Success = False Then
Log(LastException.Message)
Else
Log(MessageId)
'Parse the mail
Dim m As Message
m = MailParser.ParseMail(MessageText, File.DirRootExternal)
Log(m)
End If
End Sub

Sub Activity_Pause(UserClosed As Boolean)

End Sub
Sub Activity_Resume

End Sub
 

sacad

Member
Licensed User
Longtime User
mailparser gmail setup

Configuring other mail clients - Gmail Help
I also did this tutorial and enabled my pop in gmail and saved changes
 

Mickster

Active Member
Licensed User
Longtime User
If your mail is being successfully downloaded (check your log to make sure you aren't receiving errors), then 'm' contains all the data from the email.

As you're looping through all the emails in the account and re-declaring 'm' every time, it's only going to hold the information from the last email it successfully downloaded. Bear in mind that if your account has a lot of emails then the device most likely wasn't able to keep up and has probably crashed due to the loop.

Anyway, to display the data from the email that is now stored in 'm', you need to create a label or something that can display the data. Use:

B4X:
m.body...
m.subject...

etc to print the different parts of your mail.
 
Top