howto handle mailto: in android webview

12,094

Solution 1

Here is a more robust version of James Gray's answer. It should handle multiple addresses (comma separated) and multiple 'cc'/'bcc' parameters:

@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {

  if (url == null) {
    return false;
  }
  if (url.startsWith("market://")) {
    view.getContext().startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
    return true;
  }
  if (url.startsWith("mailto:")) {

    try {
      List<String> to = new ArrayList<String>();
      List<String> cc = new ArrayList<String>();
      List<String> bcc = new ArrayList<String>();
      String subject = null;
      String body = null;

      url = url.replaceFirst("mailto:", "");

      String[] urlSections = url.split("&");
      if (urlSections.length >= 2) {

        to.addAll(Arrays.asList(urlSections[0].split(",")));

        for (int i = 1; i < urlSections.length; i++) {
          String urlSection = urlSections[i];
          String[] keyValue = urlSection.split("=");

          if (keyValue.length == 2) {
            String key = keyValue[0];
            String value = keyValue[1];

            value = URLDecoder.decode(value, "UTF-8");

            if (key.equals("cc")) {
              cc.addAll(Arrays.asList(url.split(",")));
            }
            else if (key.equals("bcc")) {
              bcc.addAll(Arrays.asList(url.split(",")));
            }
            else if (key.equals("subject")) {
              subject = value;
            }
            else if (key.equals("body")) {
              body = value;
            }
          }
        }
      }
      else {
        to.addAll(Arrays.asList(url.split(",")));
      }

      Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND);
      emailIntent.setType("message/rfc822");

      String[] dummyStringArray = new String[0]; // For list to array conversion
      emailIntent.putExtra(android.content.Intent.EXTRA_EMAIL, to.toArray(dummyStringArray));
      if (cc.size() > 0) {
        emailIntent.putExtra(android.content.Intent.EXTRA_CC, cc.toArray(dummyStringArray));
      }
      if (bcc.size() > 0) {
        emailIntent.putExtra(android.content.Intent.EXTRA_BCC, bcc.toArray(dummyStringArray));
      }
      if (subject != null) {
        emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, subject);
      }
      if (body != null) {
        emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, body);
      }
      view.getContext().startActivity(emailIntent);

      return true;
    }
    catch (UnsupportedEncodingException e) {
      /* Won't happen*/
    }

  }
  return false;
}

Solution 2

This is what I've got:

if (url.startsWith("mailto:")) {
    String[] blah_email = url.split(":");
    Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND);
    emailIntent.setType("text/plain");
    emailIntent.putExtra(android.content.Intent.EXTRA_EMAIL, new String[]{blah_email[1]});
    emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, what_ever_you_want_the_subject_to_be)");
    Log.v("NOTICE", "Sending Email to: " + blah_email[1] + " with subject: " + what_ever_you_want_the_subject_to_be);
    startActivity(emailIntent);
}

Since I can't see the 'before' and after... It seems like it's taking away (or adding) the bold attribute on the link - check the CSS (maybe the JavaScript/Jquery) for a:visited and see if it contains a font-weight: normal; or font-weight: bold attributes.

Solution 3

Here's a more complex version that doesn't use the MailTo class (which for some reason wouldn't parse a full mailto link correctly. It pulls email, cc, bcc, subject and body in succession so long as they exist. If they don't exist it skips them and moves on to the next. This however requires that the link creator put everything in order, if its out of order it won't work. I may make another one later that won't care which order it is in.

For those that care, this also lets direct links to market apps work as well.

@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
    if (url == null) { return false; }
    if (url.startsWith("market://")) {
        view.getContext().startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
        return true;
    }
    if (url.startsWith("mailto:")) {
        url = url.replaceFirst("mailto:", "");
        //
        String theEmail = "",
            theEmailCC = "",
            theEmailBCC = "",
            theSubject = "",
            theBody = "";
        Boolean hasEmail = true,
            hasEmailCC = url.contains("&cc="),
            hasEmailBCC = url.contains("&bcc="),
            hasSubject = url.contains("&subject="),
            hasBody = url.contains("&body=");
        int posEmail = 0,
            posEmailCC = hasEmailCC ? url.indexOf("&cc=") : 0,
            posEmailBCC = hasEmailBCC ? url.indexOf("&bcc=") : 0,
            posSubject = hasSubject ? url.indexOf("&subject=") : 0,
            posBody = hasBody ? url.indexOf("&body=") : 0;
        //
        if        (hasEmail    && hasEmailCC ) { theEmail    = url.substring(posEmail, posEmailCC - posEmail);
        } else if (hasEmail    && hasEmailBCC) { theEmail    = url.substring(posEmail, posEmailBCC - posEmail);
        } else if (hasEmail    && hasSubject ) { theEmail    = url.substring(posEmail, posSubject - posEmail);
        } else if (hasEmail    && hasBody    ) { theEmail    = url.substring(posEmail, posBody - posEmail);
        } else if (hasEmail                  ) { theEmail    = url;
        } else {                               /*theEmail    = url;*/ }

        if        (hasEmailCC  && hasEmailBCC) { theEmailCC  = url.substring(posEmailCC, posEmailBCC - posEmailCC);
        } else if (hasEmailCC  && hasSubject ) { theEmailCC  = url.substring(posEmailCC, posSubject - posEmailCC);
        } else if (hasEmailCC  && hasBody    ) { theEmailCC  = url.substring(posEmailCC, posBody - posEmailCC);
        } else if (hasEmailCC                ) { theEmailCC  = url.substring(posEmailCC);
        } else {                               /*theEmailCC  = url.substring(posEmailCC);*/ }
        theEmailCC = theEmailCC.replace("&cc=", "");

        if        (hasEmailBCC && hasSubject ) { theEmailBCC = url.substring(posEmailBCC, posSubject - posEmailBCC);
        } else if (hasEmailBCC && hasBody    ) { theEmailBCC = url.substring(posEmailBCC, posBody - posEmailBCC);
        } else if (hasEmailBCC               ) { theEmailBCC = url.substring(posEmailBCC);
        } else {                               /*theEmailBCC = url.substring(posEmailBCC);*/ }
        theEmailBCC = theEmailBCC.replace("&bcc=", "");

        if        (hasSubject  && hasBody    ) { theSubject  = url.substring(posSubject, posBody - posSubject);
        } else if (hasSubject                ) { theSubject  = url.substring(posSubject);
        } else {                               /*theSubject  = url.substring(posSubject);*/ }
        theSubject = theSubject.replace("&subject=", "");

        if        (hasBody                   ) { theBody     = url.substring(posBody);
        } else {                               /*theBody     = url.substring(posBody);*/ }
        theBody = theBody.replace("&body=", "");

        theSubject = theSubject.replace("%20", " ");
        theBody = theBody.replace("%20", " ").replace("%0A", "\n");
        //
        Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND);
        emailIntent.setType("message/rfc822");
        //
        emailIntent.putExtra(android.content.Intent.EXTRA_EMAIL, new String[] { theEmail, });
        if (hasEmailCC) { emailIntent.putExtra(android.content.Intent.EXTRA_CC, theEmailCC); }
        if (hasEmailBCC) { emailIntent.putExtra(android.content.Intent.EXTRA_BCC, theEmailBCC); }
        if (hasSubject) { emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, theSubject); }
        if (hasBody) { emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, theBody); }
        //
        view.getContext().startActivity(emailIntent);
        //
        return true;
    }
    return false;
}
Share:
12,094
Nathan Schwermann
Author by

Nathan Schwermann

Android developer with over a decade of experience, I have written applications used by millions of users. I have a passion for learning and self development.

Updated on June 04, 2022

Comments

  • Nathan Schwermann
    Nathan Schwermann almost 2 years

    I am trying to intercept mailto: links in an embedded webview in my app. What I have is working ok, except when the user presses the link it is blurred upon returning to the app. Here is what I am doing in my WebViewClient

        @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        if(url.startsWith("mailto:")){
            url = url.replaceFirst("mailto:", "");
            url = url.trim();
            Intent i = new Intent(Intent.ACTION_SEND);
            i.setType("plain/text").putExtra(Intent.EXTRA_EMAIL, new String[]{url});
            context.startActivity(i);
            return true;
        }
        context.findViewById(R.id.loadingBar).setVisibility(View.VISIBLE);
        view.loadUrl(url);
        return true;
    }
    

    If I do a view.reload() it does fix the problem, but is there a better way to fix it without wasting the bandwidth? I tried invalidate() but it didn't work.

    here is an example of what I'm talking about alt text